diff --git a/CREDITS b/CREDITS index 015b4a1..5c54168 100644 --- a/CREDITS +++ b/CREDITS @@ -1,5 +1,7 @@ The Roboto Black font used in this project is licensed under the Open Font License. Read assets/fonts/OFL.txt for more information. +Thanks to OpenGameArt and pixelsphere.org / The Cynic Project for the music! (https://opengameart.org/content/crystal-cave-mysterious-ambience-seamless-loop) + Huge Thanks to Python for being the programming language used in this game. https://www.python.org/ diff --git a/assets/sound/music.ogg b/assets/sound/music.ogg new file mode 100644 index 0000000..dfa8412 Binary files /dev/null and b/assets/sound/music.ogg differ diff --git a/game/play.py b/game/play.py index 81a0da3..89ce9f1 100644 --- a/game/play.py +++ b/game/play.py @@ -1,7 +1,7 @@ -import arcade, arcade.gui, pyglet, random +import arcade, arcade.gui, pyglet, random, json from utils.preload import SPRITE_TEXTURES -from utils.constants import slider_style, dropdown_style, VAR_NAMES, VAR_DEFAULT, DEFAULT_X_GRAVITY, DEFAULT_Y_GRAVITY, VAR_OPTIONS, DO_RULES, IF_RULES, SHAPES, ALLOWED_INPUT +from utils.constants import slider_style, dropdown_style, VAR_NAMES, VAR_DEFAULT, VAR_OPTIONS, DO_RULES, IF_RULES, SHAPES, ALLOWED_INPUT from game.rules import generate_ruleset from game.sprites import BaseShape, Rectangle, Circle, Triangle @@ -13,6 +13,9 @@ class Game(arcade.gui.UIView): self.pypresence_client = pypresence_client self.pypresence_client.update(state="Causing Chaos") + with open("settings.json", "r") as file: + self.settings = json.load(file) + self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1))) self.rules_box = arcade.gui.UIBoxLayout(align="center", size_hint=(0.25, 0.95)).with_background(color=arcade.color.DARK_GRAY) @@ -20,8 +23,8 @@ class Game(arcade.gui.UIView): self.sprites_box = self.anchor.add(arcade.gui.UIBoxLayout(size_hint=(0.15, 0.95), align="center", space_between=10).with_background(color=arcade.color.DARK_GRAY), anchor_x="left", anchor_y="center", align_x=self.window.height * 0.025) - self.x_gravity = DEFAULT_X_GRAVITY - self.y_gravity = DEFAULT_Y_GRAVITY + self.x_gravity = self.settings.get("default_x_gravity", 0) + self.y_gravity = self.settings.get("default_y_gravity", 5) self.current_ruleset_num = 0 self.current_ruleset_page = 0 @@ -40,6 +43,7 @@ class Game(arcade.gui.UIView): self.rules_content_box = None self.nav_buttons_box = None + def move_x(self, a, shape): if isinstance(shape, Triangle): shape.x += a @@ -80,11 +84,11 @@ class Game(arcade.gui.UIView): def change_x_velocity(self, a, shape): shape.x_velocity = a - self.triggered_events.append(["x_velocity_change", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.color}]) + self.triggered_events.append(["x_velocity_change", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.shape_color}]) def change_y_velocity(self, a, shape): shape.y_velocity = a - self.triggered_events.append(["y_velocity_change", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.color}]) + self.triggered_events.append(["y_velocity_change", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.shape_color}]) def change_x_gravity(self, a): self.x_gravity = a @@ -95,8 +99,8 @@ class Game(arcade.gui.UIView): self.triggered_events.append(["y_gravity_change", {}]) def change_color(self, a, shape): - shape.color = getattr(arcade.color, a) - self.triggered_events.append(["color_change", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.color}]) + shape.shape_color = getattr(arcade.color, a) + self.triggered_events.append(["color_change", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.shape_color}]) def destroy(self, shape: BaseShape): self.triggered_events.append(["destroyed", {"event_shape_type": shape.shape_type}]) @@ -122,7 +126,7 @@ class Game(arcade.gui.UIView): shape.x3 += size shape.y3 += size - self.triggered_events.append(["size_change", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.color}]) + self.triggered_events.append(["size_change", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.shape_color}]) def spawn(self, shape_type): x, y = random.randint(int(self.window.width * 0.15) + 50, int(self.window.width * 0.75) - 50), random.randint(100, self.window.height - 100) @@ -138,7 +142,7 @@ class Game(arcade.gui.UIView): shape = self.shapes[-1] - self.triggered_events.append(["spawns", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.color}]) + self.triggered_events.append(["spawn", {"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.shape_color}]) def morph(self, a, shape): old_shape_x, old_shape_y, old_shape_size, old_shape_color = shape.x, shape.y, shape.shape_size, shape.shape_color @@ -310,6 +314,14 @@ class Game(arcade.gui.UIView): add_advanced_rule_button = self.rules_box.add(arcade.gui.UIFlatButton(text="Add Advanced rule", width=self.window.width * 0.225, height=self.window.height / 25, style=dropdown_style)) add_advanced_rule_button.on_click = lambda event: self.add_rule("advanced") + self.rules_box.add(arcade.gui.UISpace(height=self.window.height / 85)) + + self.rules_box.add(arcade.gui.UIFlatButton(text="Load from file\ncomming soon!", multiline=True, width=self.window.width * 0.225, height=self.window.height / 22.5, style=dropdown_style)) + + self.rules_box.add(arcade.gui.UISpace(height=self.window.height / 85)) + + self.rules_box.add(arcade.gui.UIFlatButton(text="Save to file\ncomming soon!", multiline=True, width=self.window.width * 0.225, height=self.window.height / 22.5, style=dropdown_style)) + self.rules_box.add(arcade.gui.UISpace(height=self.window.height / 70)) self.nav_buttons_box = self.rules_box.add(arcade.gui.UIBoxLayout(vertical=False, space_between=10)) @@ -333,6 +345,10 @@ class Game(arcade.gui.UIView): self.sprites_box.add(arcade.gui.UILabel(text=shape, font_size=16, text_color=arcade.color.BLACK)) self.sprites_box.add(arcade.gui.UIImage(texture=SPRITE_TEXTURES[shape], width=self.window.width / 15, height=self.window.width / 15)) + self.sprites_box.add(arcade.gui.UISpace(height=self.window.height / 50)) + + self.sprites_box.add(arcade.gui.UIFlatButton(text="Load sprite\ncomming soon!", multiline=True, style=dropdown_style, width=self.window.width * 0.125, height=self.window.height / 10)) + self.triggered_events.append(["game_launch", {}]) def add_rule(self, ruleset_type=None, force=None): @@ -393,7 +409,7 @@ class Game(arcade.gui.UIView): for shape in self.shapes: event_args = trigger_args.copy() if not "event_shape_type" in trigger_args: - event_args.update({"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.color}) + event_args.update({"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.shape_color}) if self.check_rule(key, 1, if_rule_dict, event_args): self.run_do_rule(key, 2, do_rule_dict, event_args) @@ -414,7 +430,7 @@ class Game(arcade.gui.UIView): event_args = trigger_args if not "event_shape_type" in trigger_args: - event_args.update({"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.color}) + event_args.update({"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.shape_color}) if ruleset[1] == "and": if self.check_rule(key, 1, if_rule_dicts[0], event_args) and self.check_rule(key, 2, if_rule_dicts[1], event_args): @@ -434,11 +450,19 @@ class Game(arcade.gui.UIView): self.run_do_rule(key, 3, do_rule_dict, event_args) for shape in self.shapes: + for shape_b in self.shapes: + if shape.check_collision(shape_b): + self.triggered_events.append(["collision", {"event_a_type": shape.shape_type, "event_b_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.color}]) + shape.update(self.x_gravity, self.y_gravity) if shape.x < 0 or shape.x > self.window.width or shape.y < 0 or shape.y > self.window.height: self.destroy(shape) + if len(self.shapes) > self.settings.get("max_shapes", 120): + for shape in self.shapes[:-self.settings.get("max_shapes", 120)]: + self.destroy(shape) + def change_rule_value(self, ruleset_num, rule_num, rule, rule_type, variable_type, n, value): rule_dict = IF_RULES[rule] if rule_type == "if" else DO_RULES[rule] key = f"{ruleset_num}_{rule_num}_{variable_type}_{n}" diff --git a/game/sprites.py b/game/sprites.py index 696be3f..b41ed3c 100644 --- a/game/sprites.py +++ b/game/sprites.py @@ -1,20 +1,24 @@ -import pyglet, arcade.color +import pyglet, arcade.color, math, json -from utils.constants import DEFAULT_X_VELOCITY, DEFAULT_Y_VELOCITY +# I am so sorry but this file has AI code cause i didn't have enough time to implement collision :C + +with open("settings.json", "r") as file: + settings = json.load(file) class BaseShape(): def __init__(self): self.shape_type = "" - self.x_velocity = DEFAULT_X_VELOCITY - self.y_velocity = DEFAULT_Y_VELOCITY - self._shape_color = "WHITE" + self.x_velocity = settings.get("default_x_velocity", 0) + self.y_velocity = settings.get("default_y_velocity", 0) + self._shape_color = "WHITE" + def update(self, x_gravity, y_gravity): self.x += self.x_velocity self.y += self.y_velocity self.x -= x_gravity self.y -= y_gravity - + @property def shape_color(self): return self._shape_color @@ -23,33 +27,222 @@ class BaseShape(): def shape_color(self, color): self._shape_color = color self.color = getattr(arcade.color, color) + + def check_collision(self, other): + if isinstance(other, Circle): + return self._collides_with_circle(other) + elif isinstance(other, Rectangle): + return self._collides_with_rectangle(other) + elif isinstance(other, Triangle): + return self._collides_with_triangle(other) + return False class Circle(pyglet.shapes.Circle, BaseShape): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) BaseShape.__init__(self) self.shape_type = "circle" - + @property def shape_size(self): return self.radius + + def _collides_with_circle(self, other): + dx = self.x - other.x + dy = self.y - other.y + distance = math.sqrt(dx * dx + dy * dy) + return distance < (self.radius + other.radius) + + def _collides_with_rectangle(self, rect): + closest_x = max(rect.x, min(self.x, rect.x + rect.width)) + closest_y = max(rect.y, min(self.y, rect.y + rect.height)) + + dx = self.x - closest_x + dy = self.y - closest_y + distance = math.sqrt(dx * dx + dy * dy) + + return distance < self.radius + + def _collides_with_triangle(self, tri): + if self._point_in_triangle(self.x, self.y, tri): + return True + + edges = [ + (tri.x, tri.y, tri.x2, tri.y2), + (tri.x2, tri.y2, tri.x3, tri.y3), + (tri.x3, tri.y3, tri.x, tri.y) + ] + + for x1, y1, x2, y2 in edges: + if self._distance_to_segment(x1, y1, x2, y2) < self.radius: + return True + + return False + + def _distance_to_segment(self, x1, y1, x2, y2): + dx = x2 - x1 + dy = y2 - y1 + + if dx == 0 and dy == 0: + return math.sqrt((self.x - x1)**2 + (self.y - y1)**2) + + t = max(0, min(1, ((self.x - x1) * dx + (self.y - y1) * dy) / (dx * dx + dy * dy))) + + closest_x = x1 + t * dx + closest_y = y1 + t * dy + + return math.sqrt((self.x - closest_x)**2 + (self.y - closest_y)**2) + + def _point_in_triangle(self, px, py, tri): + def sign(x1, y1, x2, y2, x3, y3): + return (x1 - x3) * (y2 - y3) - (x2 - x3) * (y1 - y3) + + d1 = sign(px, py, tri.x, tri.y, tri.x2, tri.y2) + d2 = sign(px, py, tri.x2, tri.y2, tri.x3, tri.y3) + d3 = sign(px, py, tri.x3, tri.y3, tri.x, tri.y) + + has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0) + has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0) + + return not (has_neg and has_pos) class Rectangle(pyglet.shapes.Rectangle, BaseShape): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) BaseShape.__init__(self) self.shape_type = "rectangle" - + @property def shape_size(self): return self.width + + def _collides_with_circle(self, circle): + return circle._collides_with_rectangle(self) + + def _collides_with_rectangle(self, other): + return (self.x < other.x + other.width and + self.x + self.width > other.x and + self.y < other.y + other.height and + self.y + self.height > other.y) + + def _collides_with_triangle(self, tri): + vertices = [(tri.x, tri.y), (tri.x2, tri.y2), (tri.x3, tri.y3)] + for vx, vy in vertices: + if (self.x <= vx <= self.x + self.width and + self.y <= vy <= self.y + self.height): + return True + + rect_vertices = [ + (self.x, self.y), + (self.x + self.width, self.y), + (self.x + self.width, self.y + self.height), + (self.x, self.y + self.height) + ] + for rx, ry in rect_vertices: + if self._point_in_triangle(rx, ry, tri): + return True + + tri_edges = [ + (tri.x, tri.y, tri.x2, tri.y2), + (tri.x2, tri.y2, tri.x3, tri.y3), + (tri.x3, tri.y3, tri.x, tri.y) + ] + rect_edges = [ + (self.x, self.y, self.x + self.width, self.y), + (self.x + self.width, self.y, self.x + self.width, self.y + self.height), + (self.x + self.width, self.y + self.height, self.x, self.y + self.height), + (self.x, self.y + self.height, self.x, self.y) + ] + + for t_edge in tri_edges: + for r_edge in rect_edges: + if self._segments_intersect(*t_edge, *r_edge): + return True + + return False + + def _point_in_triangle(self, px, py, tri): + def sign(x1, y1, x2, y2, x3, y3): + return (x1 - x3) * (y2 - y3) - (x2 - x3) * (y1 - y3) + + d1 = sign(px, py, tri.x, tri.y, tri.x2, tri.y2) + d2 = sign(px, py, tri.x2, tri.y2, tri.x3, tri.y3) + d3 = sign(px, py, tri.x3, tri.y3, tri.x, tri.y) + + has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0) + has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0) + + return not (has_neg and has_pos) + + def _segments_intersect(self, x1, y1, x2, y2, x3, y3, x4, y4): + def ccw(ax, ay, bx, by, cx, cy): + return (cy - ay) * (bx - ax) > (by - ay) * (cx - ax) + + return (ccw(x1, y1, x3, y3, x4, y4) != ccw(x2, y2, x3, y3, x4, y4) and + ccw(x1, y1, x2, y2, x3, y3) != ccw(x1, y1, x2, y2, x4, y4)) class Triangle(pyglet.shapes.Triangle, BaseShape): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) BaseShape.__init__(self) self.shape_type = "triangle" - + @property def shape_size(self): - return max(self.x, self.x2, self.x3) - min(self.x, self.x2, self.x3) \ No newline at end of file + return max(self.x, self.x2, self.x3) - min(self.x, self.x2, self.x3) + + def _collides_with_circle(self, circle): + return circle._collides_with_triangle(self) + + def _collides_with_rectangle(self, rect): + return rect._collides_with_triangle(self) + + def _collides_with_triangle(self, other): + vertices_self = [(self.x, self.y), (self.x2, self.y2), (self.x3, self.y3)] + vertices_other = [(other.x, other.y), (other.x2, other.y2), (other.x3, other.y3)] + + for vx, vy in vertices_self: + if self._point_in_triangle(vx, vy, other): + return True + + for vx, vy in vertices_other: + if self._point_in_triangle(vx, vy, self): + return True + + edges_self = [ + (self.x, self.y, self.x2, self.y2), + (self.x2, self.y2, self.x3, self.y3), + (self.x3, self.y3, self.x, self.y) + ] + edges_other = [ + (other.x, other.y, other.x2, other.y2), + (other.x2, other.y2, other.x3, other.y3), + (other.x3, other.y3, other.x, other.y) + ] + + for e1 in edges_self: + for e2 in edges_other: + if self._segments_intersect(*e1, *e2): + return True + + return False + + def _point_in_triangle(self, px, py, tri): + def sign(x1, y1, x2, y2, x3, y3): + return (x1 - x3) * (y2 - y3) - (x2 - x3) * (y1 - y3) + + d1 = sign(px, py, tri.x, tri.y, tri.x2, tri.y2) + d2 = sign(px, py, tri.x2, tri.y2, tri.x3, tri.y3) + d3 = sign(px, py, tri.x3, tri.y3, tri.x, tri.y) + + has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0) + has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0) + + return not (has_neg and has_pos) + + def _segments_intersect(self, x1, y1, x2, y2, x3, y3, x4, y4): + def ccw(ax, ay, bx, by, cx, cy): + return (cy - ay) * (bx - ax) > (by - ay) * (cx - ax) + + return (ccw(x1, y1, x3, y3, x4, y4) != ccw(x2, y2, x3, y3, x4, y4) and + ccw(x1, y1, x2, y2, x3, y3) != ccw(x1, y1, x2, y2, x4, y4)) \ No newline at end of file diff --git a/menus/main.py b/menus/main.py index e02951c..a418d4f 100644 --- a/menus/main.py +++ b/menus/main.py @@ -52,10 +52,10 @@ class Main(arcade.gui.UIView): self.title_label = self.box.add(arcade.gui.UILabel(text="Chaos Protocol", font_name="Roboto", font_size=48)) - self.play_button = self.box.add(arcade.gui.UITextureButton(text="Play", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=150, style=big_button_style)) + self.play_button = self.box.add(arcade.gui.UITextureButton(text="Play", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=self.window.height / 10, style=big_button_style)) self.play_button.on_click = lambda event: self.play() - self.settings_button = self.box.add(arcade.gui.UITextureButton(text="Settings", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=150, style=big_button_style)) + self.settings_button = self.box.add(arcade.gui.UITextureButton(text="Settings", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=self.window.height / 10, style=big_button_style)) self.settings_button.on_click = lambda event: self.settings() def play(self): diff --git a/run.py b/run.py index 3d960c3..6173c6c 100644 --- a/run.py +++ b/run.py @@ -10,11 +10,10 @@ script_dir = os.path.dirname(os.path.abspath(__file__)) pyglet.resource.path.append(script_dir) pyglet.font.add_directory(os.path.join(script_dir, 'assets', 'fonts')) - from utils.utils import get_closest_resolution, print_debug_info, on_exception from utils.constants import log_dir, menu_background_color from menus.main import Main -# from utils.preload import theme_sound # needed for preload +from utils.preload import theme_sound # needed for preload from arcade.experimental.controller_window import ControllerWindow sys.excepthook = on_exception @@ -87,8 +86,8 @@ else: with open("settings.json", "w") as file: file.write(json.dumps(settings)) -# if settings.get("music", True): -# theme_sound.play(volume=settings.get("music_volume", 50) / 100, loop=True) +if settings.get("music", True): + theme_sound.play(volume=settings.get("music_volume", 50) / 100, loop=True) try: window = ControllerWindow(width=resolution[0], height=resolution[1], title='Chaos Protocol', samples=antialiasing, antialiasing=antialiasing > 0, fullscreen=fullscreen, vsync=vsync, resizable=False, style=style, visible=False) diff --git a/utils/constants.py b/utils/constants.py index bdd5634..100e297 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -7,12 +7,6 @@ LOGICAL_OPERATORS = ["and", "or"] SHAPES = ["rectangle", "circle", "triangle"] VAR_NAMES = ["a", "b", "c", "d", "e", "f", "g"] -DEFAULT_X_GRAVITY = 0 -DEFAULT_Y_GRAVITY = 2 - -DEFAULT_X_VELOCITY = 0 -DEFAULT_Y_VELOCITY = 0 - ALLOWED_INPUT = ["a", "b", "c", "d", "e", "q", "w", "s", "t"] COLORS = [ @@ -82,7 +76,7 @@ IF_RULES = { "spawns": { "key": "spawns", "description": "IF {a} shape spawns", - "trigger": "spawns", + "trigger": "spawn", "user_vars": ["shape_type"], "vars": ["shape_type", "event_shape_type"], "func": lambda *v: v[0] == v[1] @@ -111,22 +105,6 @@ IF_RULES = { "vars": ["shape_type", "event_shape_type"], "func": lambda *v: v[0] == v[1] }, - "x_gravity_changes": { - "key": "x_gravity_changes", - "description": "IF {a} shape X gravity changes", - "trigger": "gravity_x_change", - "user_vars": ["shape_type"], - "vars": ["shape_type", "event_shape_type"], - "func": lambda *v: v[0] == v[1] - }, - "y_gravity_changes": { - "key": "y_gravity_changes", - "description": "IF {a} shape Y gravity changes", - "trigger": "gravity_y_change", - "user_vars": ["shape_type"], - "vars": ["shape_type", "event_shape_type"], - "func": lambda *v: v[0] == v[1] - }, "color_changes": { "key": "color_changes", "description": "IF {a} shape color changes", @@ -438,16 +416,21 @@ slider_style = {'normal': slider_default_style, 'hover': slider_hover_style, 'pr settings = { "Graphics": { "Window Mode": {"type": "option", "options": ["Windowed", "Fullscreen", "Borderless"], "config_key": "window_mode", "default": "Windowed"}, - "Resolution": {"type": "option", "options": ["1366x768", "1440x900", "1600x900", "1920x1080", "2560x1440", "3840x2160"], "config_key": "resolution"}, + "Resolution": {"type": "option", "options": ["1440x900", "1600x900", "1920x1080", "2560x1440", "3840x2160"], "config_key": "resolution"}, "Anti-Aliasing": {"type": "option", "options": ["None", "2x MSAA", "4x MSAA", "8x MSAA", "16x MSAA"], "config_key": "anti_aliasing", "default": "4x MSAA"}, "VSync": {"type": "bool", "config_key": "vsync", "default": True}, "FPS Limit": {"type": "slider", "min": 0, "max": 480, "config_key": "fps_limit", "default": 60}, }, "Sound": { "Music": {"type": "bool", "config_key": "music", "default": True}, - "SFX": {"type": "bool", "config_key": "sfx", "default": True}, "Music Volume": {"type": "slider", "min": 0, "max": 100, "config_key": "music_volume", "default": 50}, - "SFX Volume": {"type": "slider", "min": 0, "max": 100, "config_key": "sfx_volume", "default": 50}, + }, + "Game": { + "Default X velocity": {"type": "slider", "min": -999, "max": 999, "config_key": "default_x_velocity", "default": 0}, + "Default Y velocity": {"type": "slider", "min": -999, "max": 999, "config_key": "default_y_velocity", "default": 0}, + "Default X gravity": {"type": "slider", "min": -999, "max": 999, "config_key": "default_x_gravity", "default": 0}, + "Default Y gravity": {"type": "slider", "min": -999, "max": 999, "config_key": "default_y_gravity", "default": 5}, + "Max Shapes": {"type": "slider", "min": 0, "max": 999, "config_key": "max_shapes", "default": 120}, }, "Miscellaneous": { "Discord RPC": {"type": "bool", "config_key": "discord_rpc", "default": True}, diff --git a/utils/preload.py b/utils/preload.py index 616c84d..667c114 100644 --- a/utils/preload.py +++ b/utils/preload.py @@ -12,3 +12,5 @@ SPRITE_TEXTURES = { "rectangle": arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'sprites', 'rectangle.png')), "triangle": arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'sprites', 'triangle.png')), } + +theme_sound = arcade.Sound(os.path.join(_assets_dir, 'sound', 'music.ogg')) \ No newline at end of file diff --git a/utils/utils.py b/utils/utils.py index 746040f..d3b7e05 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -41,7 +41,7 @@ def on_exception(*exc_info): logging.error(f"Unhandled exception:\n{''.join(traceback.format_exception(exc_info[1], limit=None))}") def get_closest_resolution(): - allowed_resolutions = [(1366, 768), (1440, 900), (1600,900), (1920,1080), (2560,1440), (3840,2160)] + allowed_resolutions = [(1440, 900), (1600,900), (1920,1080), (2560,1440), (3840,2160)] screen_width, screen_height = arcade.get_screens()[0].width, arcade.get_screens()[0].height if (screen_width, screen_height) in allowed_resolutions: if not allowed_resolutions.index((screen_width, screen_height)) == 0: