Skip to content

Commit

Permalink
2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
quasar098 committed Jun 15, 2023
1 parent 57ba9a8 commit 74ccf43
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 71 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ cant remember where i got the others from (sorry if i stole midi file)

mainmenu.mp3 song is Aerial City by Chika for tetr.io (will replace later, but this is fine for now i think)

if you do not enjoy me using your midi or songs, i can remove it from this project and replace them
death sound is undertale gaster fade

colors generated using [coolors.co](https://coolors.co/generate)

if you do not enjoy me using your assets, i can remove it from this project and replace them with other things

## contributors

Expand All @@ -35,22 +39,21 @@ if you do not enjoy me using your midi or songs, i can remove it from this proje

### generic

- redo scoring because it currently sucks
- visual aid for timing
- life bar
- prevent spamming during scoring
- visual aid for timing of square bounce (ghost square where next bounce?)
- see entire map at the end
- implement modifiers like osu (DT, HR, HD, EZ, etc)
- midi text events at specific timestamps to change the speed of the cube
- more songs
- map editor if time
- rectangle duplicate overlap area remover for hallways
- add monitor framerate finder for linux (not macos b/c i hate mac users) [link here](https://stackoverflow.com/questions/1225057/how-can-i-determine-the-monitor-refresh-rate)
- reset to default button for config page
- square bounce intensity, particle intensity (sorry, TheCodingCrafter! merge conflicts strike again)
- i think there are sync issues idk
- keystrokes icons for space, arrow keys before reactivating arrow keys and space
- 4 key gamemode

### modifiers

- light switch that turns on and off at each bounce ? (flashlight)
- precise mode (no 100s, only 300s or misses)
- theatre mode (no scoring)
Binary file added assets/basehiticon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/death.mp3
Binary file not shown.
Binary file added assets/early.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/good.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/late.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/miss.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/perfect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 9 additions & 1 deletion config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ class Config:
PARTICLE_SPEED = 10

# colors
#
# each color theme requires a hallway color, a background color, and at least one square color
# optionally, the color theme provides an hp_bar_border color (default 10, 9, 8),
# an hp_bar_background color (default 34, 51, 59), and a list
# of hp_bar_fill colors (default (156, 198, 155), (189, 228, 168), (215, 242, 186))
#
color_themes = {
"dark": {
"hallway": pygame.Color(214, 209, 205),
Expand Down Expand Up @@ -105,6 +111,8 @@ class Config:
volume: Optional[int] = 70
music_offset: Optional[int] = -300
direction_change_chance: Optional[int] = 30
hp_drain_rate = 10
theatre_mode = False

# settings that are not configurable (yet)
backtrack_chance: Optional[float] = 0.01
Expand All @@ -119,7 +127,7 @@ class Config:

# keys to save and load
save_attrs = ["theme", "seed", "camera_mode", "start_playing_delay", "max_notes", "bounce_min_spacing",
"square_speed", "volume", "music_offset", "direction_change_chance"]
"square_speed", "volume", "music_offset", "direction_change_chance", "hp_drain_rate", "theatre_mode"]


def get_colors():
Expand Down
30 changes: 30 additions & 0 deletions configpage.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ def __init__(self):
manager=self.ui_manager
)

self.s_hp_drain_rate = pgui.elements.UIHorizontalSlider(
relative_rect=pygame.Rect((300, 510, 300, 30)),
start_value=Config.hp_drain_rate,
value_range=(3, 20),
manager=self.ui_manager
)
self.s_hp_drain_rate_label = pgui.elements.UILabel(
relative_rect=pygame.Rect((30, 510, 240, 30)),
text=f"HP drain rate ({Config.hp_drain_rate}/s):",
manager=self.ui_manager
)

# audio and general settings

self.s_game_volume = pgui.elements.UIHorizontalSlider(
Expand All @@ -147,6 +159,18 @@ def __init__(self):
manager=self.ui_manager
)

self.s_theatre_mode = pgui.elements.UIDropDownMenu(
["Off", "On"],
relative_rect=pygame.Rect((930, 150, 300, 30)),
starting_option=["Off", "On"][int(Config.theatre_mode)],
manager=self.ui_manager
)
self.s_theatre_mode_label = pgui.elements.UILabel(
relative_rect=pygame.Rect((630, 150, 240, 30)),
text="Theatre mode:",
manager=self.ui_manager
)

def handle_event(self, event: pygame.event.Event):
if not self.active:
return
Expand All @@ -168,6 +192,9 @@ def handle_event(self, event: pygame.event.Event):
if event.ui_element == self.s_color_theme:
play_sound("wood.wav")
Config.theme = event.text
if event.ui_element == self.s_theatre_mode:
play_sound("wood.wav")
Config.theatre_mode = bool("fn".index(event.text[1]))

if event.type == pgui.UI_TEXT_ENTRY_CHANGED:
if event.ui_element == self.s_seed:
Expand Down Expand Up @@ -203,6 +230,9 @@ def handle_event(self, event: pygame.event.Event):
if event.ui_element == self.s_direction_change_chance:
self.s_direction_change_chance_label.set_text(f"Change dir chance ({event.value}%):")
Config.direction_change_chance = event.value
if event.ui_element == self.s_hp_drain_rate:
self.s_hp_drain_rate_label.set_text(f"HP drain rate ({event.value}/s):")
Config.hp_drain_rate = event.value

self.ui_manager.process_events(event)

Expand Down
74 changes: 52 additions & 22 deletions game.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from world import World
import random
from camera import Camera
from keystrokes import Keystrokes
from particle import Particle


Expand All @@ -17,6 +18,8 @@ def __init__(self):
self.music_has_played = False
self.offset_happened = False
self.loading_text = get_font("./assets/poppins-regular.ttf", 24).render("Loading...", True, (255, 255, 255))
self.try_again_text = get_font("./assets/poppins-regular.ttf", 36).render("Press escape to go back", True, (255, 255, 255))
self.keystrokes = Keystrokes()

def start_song(self, screen: pygame.Surface, song_path: str = None):
random.seed(Config.seed)
Expand Down Expand Up @@ -62,7 +65,6 @@ def update_loading_screen(pdone: int):
self.world.square.pos = self.world.future_bounces[0].square_pos

def draw(self, screen: pygame.Surface):
self.world.scorekeeper.penalize_misses(self.world.time)

if not self.active:
return
Expand Down Expand Up @@ -129,24 +131,50 @@ def draw(self, screen: pygame.Surface):
self.world.particles.remove(remove_particle)

# scorekeeper drawing
mimic = get_font("./assets/poppins-regular.ttf", 24).render(self.world.scorekeeper.latest_message, True, (255, 255, 255))
screen.blit(mimic, (100, 100))
time_from_start = self.world.time-Config.start_playing_delay/1000+Config.music_offset/1000
if not Config.theatre_mode:
self.world.scorekeeper.draw(screen, time_from_start if len(self.world.future_bounces) else -1)

# hit icons
to_remove = []
for hiticon in self.world.scorekeeper.hit_icons:
if hiticon.draw(screen, self.camera):
to_remove.append(hiticon)
for remove in to_remove:
self.world.scorekeeper.hit_icons.remove(remove)

if self.world.scorekeeper.hp <= 0 and not self.world.square.died:
self.world.square.died = True
self.world.square.dir = [0, 0]
pygame.mixer.music.stop()
play_sound("death.mp3", 0.5)
self.world.future_bounces = []
for _ in range(100):
self.world.particles.append(Particle(self.world.square.pos, [random.randint(-3, 3), random.randint(-3, 3)]))
if self.world.square.died:
self.world.scorekeeper.hp = 0

# draw square
self.world.square.draw(screen, sqrect)

# countdown to start
time_from_start = self.world.time-Config.start_playing_delay/1000+Config.music_offset/1000
if time_from_start < 0:
repr_time = f"{abs(int((time_from_start+0.065)*10)/10)}s"
countdown_surface = get_font("./assets/poppins-regular.ttf", 36).render(repr_time, True, (255, 255, 255))
screen.blit(countdown_surface, countdown_surface.get_rect(center=(Config.SCREEN_WIDTH/2, Config.SCREEN_HEIGHT/4)))
elif time_from_start < 0.5:
repr_zero = f"0.0s"
countdown_surface = get_font("./assets/poppins-regular.ttf", 36).render(repr_zero, True, (255, 255, 255))
countdown_surface.set_alpha((0.5-time_from_start)*2*255)
screen.blit(countdown_surface, countdown_surface.get_rect(center=(Config.SCREEN_WIDTH/2, Config.SCREEN_HEIGHT/4)))

if not Config.theatre_mode:
# keystrokes
self.keystrokes.draw(screen)

# countdown to start
if time_from_start < 0:
repr_time = f"{abs(int((time_from_start+0.065)*10)/10)}s"
countdown_surface = get_font("./assets/poppins-regular.ttf", 36).render(repr_time, True, (255, 255, 255))
screen.blit(countdown_surface, countdown_surface.get_rect(center=(Config.SCREEN_WIDTH/2, Config.SCREEN_HEIGHT/4)))
elif time_from_start < 0.5:
repr_zero = f"0.0s"
countdown_surface = get_font("./assets/poppins-regular.ttf", 36).render(repr_zero, True, (255, 255, 255))
countdown_surface.set_alpha((0.5-time_from_start)*2*255)
screen.blit(countdown_surface, countdown_surface.get_rect(center=(Config.SCREEN_WIDTH/2, Config.SCREEN_HEIGHT/4)))

# failure message
if self.world.square.died:
screen.blit(self.try_again_text, self.try_again_text.get_rect(center=(Config.SCREEN_WIDTH/2, Config.SCREEN_HEIGHT/4)))
if not self.camera.locked_on_square:
screen.blit(self.camera_ctrl_text, (10, 10))

Expand All @@ -162,10 +190,12 @@ def handle_event(self, event: pygame.event.Event):
return True
if event.key == pygame.K_TAB:
self.camera.locked_on_square = not self.camera.locked_on_square
if self.camera.locked_on_square:
time_from_start = self.world.time-Config.start_playing_delay/1000+Config.music_offset/1000
if time_from_start < 0:
return
arrows_n_space = pygame.K_SPACE, pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN
if 97+26 > event.key >= 97 or event.key in arrows_n_space: # press a to z key or space or arrows
self.world.handle_keypress()
if not Config.theatre_mode:
if self.camera.locked_on_square:
time_from_start = self.world.time-Config.start_playing_delay/1000+Config.music_offset/1000
if time_from_start < -0.2:
return
# arrows_n_space = pygame.K_SPACE, pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN
arrows_n_space = ()
if 97+26 > event.key >= 97 or event.key in arrows_n_space: # press a to z key or space or arrows
self.world.handle_keypress(time_from_start)
30 changes: 30 additions & 0 deletions hiticon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from utils import *
import pygame


class HitLevel(Enum):
early = 0
good = 1
perfect = 2
late = 3
miss = 4


class HitIcon:
surfaces: dict[HitLevel, pygame.Surface] = {}

def __init__(self, lvl: HitLevel, pos: Union[tuple[int, int], list[int]]):
if len(HitIcon.surfaces) == 0:
for level in HitLevel:
HitIcon.surfaces[level] = pygame.image.load(f"./assets/{level.name}.png").convert_alpha()

self.pos = pos
self.lvl = lvl
self.age_left = 500
self.surf = HitIcon.surfaces[lvl].copy()

def draw(self, screen: pygame.Surface, camera):
self.age_left -= 500/FRAMERATE
self.surf.set_alpha(int(max(min(self.age_left, 255), 0)))
screen.blit(self.surf, camera.offset(self.surf.get_rect(center=self.pos)))
return self.age_left <= 0
29 changes: 29 additions & 0 deletions keystrokes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from utils import *
import pygame


class Keystrokes:
def __init__(self):
self.keys: list[str] = []
self.key_surfaces: dict[str, pygame.Surface] = {}
self.chars = "abcdefghijklmnopqrstuvwxyz"
for possible_to_hit in self.chars:
self.key_surfaces[possible_to_hit] = get_font("./assets/poppins-regular.ttf", 36).render(
possible_to_hit, True, get_colors()["background"]
)

def draw(self, screen: pygame.Surface):
default_rect = pygame.Rect(10, Config.SCREEN_HEIGHT-60, 50, 50)
for _ in range(97, 97+26):
char = self.chars[_-97]
if pygame.key.get_pressed()[_]:
if char not in self.keys:
self.keys.append(char)
else:
if char in self.keys:
self.keys.remove(char)
for key in self.keys:
pygame.draw.rect(screen, (0, 0, 0), default_rect)
pygame.draw.rect(screen, get_colors()["hallway"], default_rect.inflate(-2, -2))
screen.blit(self.key_surfaces[key], self.key_surfaces[key].get_rect(center=default_rect.center))
default_rect.x += 60
Loading

0 comments on commit 74ccf43

Please sign in to comment.