diff --git a/README.md b/README.md index 6b56e55..e3fb572 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ Chaos Protocol is a simulation game where you have a rule engine and objects, which you can apply rules to! By default, the game launches with random rules. -Basically a framework of sorts, which can even be random! \ No newline at end of file +Basically a framework of sorts, which can even be random! + +The project is a huge WIP! You can't do much yet, but you have basic rules and simulation. \ No newline at end of file diff --git a/assets/graphics/sprites/circle.png b/assets/graphics/sprites/circle.png new file mode 100644 index 0000000..86c678e Binary files /dev/null and b/assets/graphics/sprites/circle.png differ diff --git a/assets/graphics/sprites/rectangle.png b/assets/graphics/sprites/rectangle.png new file mode 100644 index 0000000..af2800e Binary files /dev/null and b/assets/graphics/sprites/rectangle.png differ diff --git a/assets/graphics/sprites/triangle.png b/assets/graphics/sprites/triangle.png new file mode 100644 index 0000000..8f52370 Binary files /dev/null and b/assets/graphics/sprites/triangle.png differ diff --git a/game/play.py b/game/play.py index dd2bbcb..3783fd0 100644 --- a/game/play.py +++ b/game/play.py @@ -1,11 +1,12 @@ import arcade, arcade.gui, pyglet, random -from utils.constants import slider_style, dropdown_style, VAR_NAMES, VAR_DEFAULT, DEFAULT_GRAVITY, VAR_OPTIONS, DO_RULES, IF_RULES +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 arcade.gui.experimental.scroll_area import UIScrollArea, UIScrollBar from game.rules import generate_rule -from game.sprites import * +from game.sprites import BaseShape, Rectangle, Circle, Triangle class Game(arcade.gui.UIView): def __init__(self, pypresence_client): @@ -18,16 +19,19 @@ class Game(arcade.gui.UIView): self.scroll_area = UIScrollArea(size_hint=(0.25, 1)) # center on screen self.scroll_area.scroll_speed = -75 - self.anchor.add(self.scroll_area, anchor_x="right", anchor_y="center", align_x=-self.window.width * 0.02) + self.anchor.add(self.scroll_area, anchor_x="right", anchor_y="bottom", align_x=-self.window.width * 0.02) self.scrollbar = UIScrollBar(self.scroll_area) self.scrollbar.size_hint = (0.02, 1) self.anchor.add(self.scrollbar, anchor_x="right", anchor_y="center") - self.rules_box = arcade.gui.UIBoxLayout(align="left", size_hint=(0.25, 1)).with_background(color=arcade.color.DARK_GRAY) + self.rules_box = arcade.gui.UIBoxLayout(align="center", size_hint=(0.25, 1)).with_background(color=arcade.color.DARK_GRAY) self.scroll_area.add(self.rules_box) - self.gravity = DEFAULT_GRAVITY + self.sprites_box = self.anchor.add(arcade.gui.UIBoxLayout(size_hint=(0.15, 1), align="center", space_between=10).with_background(color=arcade.color.DARK_GRAY), anchor_x="left", anchor_y="bottom") + + self.x_gravity = DEFAULT_X_GRAVITY + self.y_gravity = DEFAULT_Y_GRAVITY self.current_ruleset_num = 0 self.rulesets = {} @@ -40,39 +44,119 @@ class Game(arcade.gui.UIView): self.shapes = [] self.shape_batch = pyglet.graphics.Batch() - def move_x(self, shape, a): - shape.x += a + def move_x(self, a, shape): + if isinstance(shape, Triangle): + shape.x += a + shape.x2 += a + shape.x3 += a + else: + shape.x += a - def move_y(self, shape, a): - shape.y += a + def move_y(self, a, shape): + if isinstance(shape, Triangle): + shape.y += a + shape.y2 += a + shape.y3 += a + else: + shape.y += a - def change_x(self, shape, a): - shape.x = a + def change_x(self, a, shape): + if isinstance(shape, Triangle): + offset_x2 = shape.x2 - shape.x + offset_x3 = shape.x3 - shape.x + + shape.x = a + shape.x2 = a + offset_x2 + shape.x3 = a + offset_x3 + else: + shape.x = a + + def change_y(self, a, shape): + if isinstance(shape, Triangle): + offset_y2 = shape.y2 - shape.y + offset_y3 = shape.y3 - shape.y + + shape.y = a + shape.y2 = a + offset_y2 + shape.y3 = a + offset_y3 + else: + shape.y = a - def change_y(self, shape, a): - shape.y = a - - def change_x_velocity(self, shape, a): + 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}]) - def change_y_velocity(self, shape, a): + 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}]) - def change_gravity(self, a): - self.gravity = a + def change_x_gravity(self, a): + self.x_gravity = a + self.triggered_events.append(["x_gravity_change", {}]) - def spawn(self, shape): - x, y = random.randint(100, self.window.width - 100), random.randint(100, self.window.height - 100) + def change_y_gravity(self, a): + self.y_gravity = a + self.triggered_events.append(["y_gravity_change", {}]) - if shape == "circle": + 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}]) + + def destroy(self, shape: BaseShape): + self.triggered_events.append(["destroyed", {"event_shape_type": shape.shape_type}]) + if shape in self.shapes: + self.shapes.remove(shape) + shape.delete() + + def change_size(self, a, shape): + if isinstance(shape, Circle): + shape.radius = a + elif isinstance(shape, Rectangle): + shape.width = a + shape.height = a + elif isinstance(shape, Triangle): + size = a - shape.shape_size + + shape.x += size + shape.y += size + + shape.x2 += size + shape.y2 += size + + 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}]) + + def spawn(self, shape_type): + x, y = random.randint(self.window.width * 0.15 + 50, self.window.width * 0.75 - 50), random.randint(100, self.window.height - 100) + + if shape_type == "circle": self.shapes.append(Circle(x, y, 10, color=arcade.color.WHITE, batch=self.shape_batch)) - elif shape == "rectangle": + elif shape_type == "rectangle": self.shapes.append(Rectangle(x, y, width=10, height=10, color=arcade.color.WHITE, batch=self.shape_batch)) - elif shape == "triangle": + elif shape_type == "triangle": self.shapes.append(Triangle(x, y, x + 10, y, x + 5, y + 10, color=arcade.color.WHITE, batch=self.shape_batch)) + 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}]) + + 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 + self.destroy(shape) + + if a == "circle": + self.shapes.append(Circle(old_shape_x, old_shape_y, old_shape_size, color=getattr(arcade.color, old_shape_color), batch=self.shape_batch)) + + elif a == "rectangle": + self.shapes.append(Rectangle(old_shape_x, old_shape_y, width=old_shape_size, height=old_shape_size, color=getattr(arcade.color, old_shape_color), batch=self.shape_batch)) + + elif a == "triangle": + self.shapes.append(Triangle(old_shape_x, old_shape_y, old_shape_x + old_shape_size, old_shape_y, old_shape_x + int(old_shape_size / 2), old_shape_y + old_shape_size, color=getattr(arcade.color, old_shape_color), batch=self.shape_batch)) + def create_rule_ui(self, rule_box: arcade.gui.UIBoxLayout, rule, rule_type, rule_num=1): rule_dict = IF_RULES[rule] if rule_type == "if" else DO_RULES[rule] @@ -81,7 +165,7 @@ class Game(arcade.gui.UIView): default_values = {VAR_NAMES[n]: VAR_DEFAULT[variable] for n, variable in enumerate(rule_dict["user_vars"])} description = rule_dict["description"].format_map(default_values) - desc_label = rule_box.add(arcade.gui.UILabel(description if rule_type == "if" else f"THEN {description}", font_size=13, width=self.window.width * 0.25)) + desc_label = rule_box.add(arcade.gui.UILabel(description, font_size=13, width=self.window.width * 0.225)) self.rule_labels[f"{self.current_ruleset_num}_{rule_num}_desc"] = desc_label for n, variable_type in enumerate(rule_dict["user_vars"]): @@ -89,16 +173,17 @@ class Game(arcade.gui.UIView): self.rule_values[key] = default_values[VAR_NAMES[n]] - label = rule_box.add(arcade.gui.UILabel(f'{VAR_NAMES[n]}: {default_values[VAR_NAMES[n]]}', font_size=11, width=self.window.width * 0.25, height=self.window.height / 25)) + label = rule_box.add(arcade.gui.UILabel(f'{VAR_NAMES[n]}: {default_values[VAR_NAMES[n]]}', font_size=11, width=self.window.width * 0.225, height=self.window.height / 25)) self.rule_labels[key] = label if variable_type in ["variable", "size"]: - slider = rule_box.add(arcade.gui.UISlider(value=default_values[VAR_NAMES[n]], min_value=VAR_OPTIONS[variable_type][0], max_value=VAR_OPTIONS[variable_type][1], step=1, style=slider_style, width=self.window.width * 0.25, height=self.window.height / 25)) + slider = rule_box.add(arcade.gui.UISlider(value=default_values[VAR_NAMES[n]], min_value=VAR_OPTIONS[variable_type][0], max_value=VAR_OPTIONS[variable_type][1], step=1, style=slider_style, width=self.window.width * 0.225, height=self.window.height / 25)) slider._render_steps = lambda surface: None slider.on_change = lambda event, variable_type=variable_type, rule=rule, rule_type=rule_type, ruleset_num=ruleset_num, rule_num=rule_num, n=n: self.change_rule_value(ruleset_num, rule_num, rule, rule_type, variable_type, n, event.new_value) self.rule_var_changers[key] = slider + elif variable_type in ["shape_type", "target_type", "color"]: - dropdown = rule_box.add(arcade.gui.UIDropdown(default=default_values[VAR_NAMES[n]], options=VAR_OPTIONS[variable_type], active_style=dropdown_style, primary_style=dropdown_style, dropdown_style=dropdown_style, width=self.window.width * 0.25, height=self.window.height / 25)) + dropdown = rule_box.add(arcade.gui.UIDropdown(default=default_values[VAR_NAMES[n]], options=VAR_OPTIONS[variable_type], active_style=dropdown_style, primary_style=dropdown_style, dropdown_style=dropdown_style, width=self.window.width * 0.225, height=self.window.height / 25)) dropdown.on_change = lambda event, variable_type=variable_type, rule=rule, rule_type=rule_type, ruleset_num=ruleset_num, rule_num=rule_num, n=n: self.change_rule_value(ruleset_num, rule_num, rule, rule_type, variable_type, n, event.new_value) self.rule_var_changers[key] = dropdown @@ -109,7 +194,7 @@ class Game(arcade.gui.UIView): self.rulesets[self.current_ruleset_num] = ruleset self.create_rule_ui(rule_box, ruleset[0], "if") - self.create_rule_ui(rule_box, ruleset[1], "do") + self.create_rule_ui(rule_box, ruleset[1], "do", 2) else: self.rulesets[self.current_ruleset_num] = ruleset @@ -124,25 +209,35 @@ class Game(arcade.gui.UIView): def on_show_view(self): super().on_show_view() - add_rule_button = self.rules_box.add(arcade.gui.UIFlatButton(text="Add rule", width=self.window.width * 0.25, height=self.window.height / 15, style=dropdown_style)) + self.rules_box.add(arcade.gui.UILabel(text="Rules", font_size=24, text_color=arcade.color.BLACK)) + self.rules_box.add(arcade.gui.UISpace(height=self.window.height / 50, width=self.window.width * 0.25)) # have to add a width of 0.25 so it doesnt resize to 0.225 + + add_rule_button = self.rules_box.add(arcade.gui.UIFlatButton(text="Add rule", width=self.window.width * 0.225, height=self.window.height / 15, style=dropdown_style)) add_rule_button.on_click = lambda event: self.add_rule() self.rules_box.add(arcade.gui.UISpace(height=self.window.height / 50)) - for _ in range(8): - self.add_rule() + self.add_rule(["on_left_click", "spawn"]) + self.add_rule(["size_greater", "morph_into"]) + + self.sprites_box.add(arcade.gui.UILabel(text="Sprites", font_size=24, text_color=arcade.color.BLACK)) + self.sprites_box.add(arcade.gui.UISpace(height=self.window.height / 50)) + + for shape in SHAPES: + self.sprites_box.add(arcade.gui.UILabel(text=shape, font_size=16)) + self.sprites_box.add(arcade.gui.UIImage(texture=SPRITE_TEXTURES[shape], width=self.window.width / 15, height=self.window.width / 15)) self.triggered_events.append(["game_launch", {}]) - def add_rule(self): - self.rulesets[self.current_ruleset_num] = generate_rule() + def add_rule(self, force=None): + self.rulesets[self.current_ruleset_num] = generate_rule() if not force else force self.add_ruleset(self.rulesets[self.current_ruleset_num]) self.current_ruleset_num += 1 def get_rule_values(self, ruleset_num, rule_num, rule_dict, event_args): args = [self.rule_values[f"{ruleset_num}_{rule_num}_{user_var}_{n}"] for n, user_var in enumerate(rule_dict["user_vars"])] - return args + [event_args[var] for var in rule_dict.get("vars", []) if var in rule_dict["user_vars"]] + return args + [event_args[var] for var in rule_dict.get("vars", []) if not var in rule_dict["user_vars"]] def check_rule(self, ruleset_num, rule_num, rule_dict, event_args): return rule_dict["func"](*self.get_rule_values(ruleset_num, rule_num, rule_dict, event_args)) @@ -151,7 +246,8 @@ class Game(arcade.gui.UIView): ACTION_FUNCTION_DICT = { "global_action": { "spawn": self.spawn, - "change_gravity": self.change_gravity + "change_x_gravity": self.change_x_gravity, + "change_y_gravity": self.change_y_gravity }, "shape_action": { "move_x": self.move_x, @@ -159,7 +255,11 @@ class Game(arcade.gui.UIView): "change_x": self.change_x, "change_y": self.change_y, "change_x_velocity": self.change_x_velocity, - "change_y_velocity": self.change_y_velocity + "change_y_velocity": self.change_y_velocity, + "change_color": self.change_color, + "change_size": self.change_size, + "destroy": self.destroy, + "morph": self.morph } } @@ -173,7 +273,6 @@ class Game(arcade.gui.UIView): while len(self.triggered_events) > 0: trigger, trigger_args = self.triggered_events.pop(0) - for key, ruleset in self.rulesets.items(): if len(ruleset) == 2: if_rule_dict = IF_RULES[ruleset[0]] @@ -182,20 +281,19 @@ class Game(arcade.gui.UIView): if not if_rule_dict["trigger"] == trigger: continue - if if_rule_dict["trigger"] in ["every_update"]: - for shape in self.shapes: - event_args = trigger_args - + if do_rule_dict["action"]["type"] == "shape_action": + 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.size}) + 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}) - if self.check_rule(key, 0, if_rule_dict, event_args): - self.run_do_rule(key, 1, do_rule_dict, event_args) + if self.check_rule(key, 1, if_rule_dict, event_args): + self.run_do_rule(key, 2, do_rule_dict, event_args) else: - event_args = trigger_args - if self.check_rule(key, 0, if_rule_dict, event_args): - self.run_do_rule(key, 1, do_rule_dict, event_args) - + event_args = trigger_args.copy() + if self.check_rule(key, 1, if_rule_dict, event_args): + self.run_do_rule(key, 2, do_rule_dict, event_args) + else: if_rule_dicts = IF_RULES[ruleset[0]], IF_RULES[ruleset[2]] do_rule_dict = DO_RULES[ruleset[3]] @@ -203,21 +301,35 @@ class Game(arcade.gui.UIView): if not (if_rule_dicts[0]["trigger"] == trigger and if_rule_dicts[0]["trigger"] == trigger): continue - for shape in self.shapes if not "event_shape_type" in trigger_args else [shape]: - event_args = trigger_args - if not "event_shape_type" in trigger_args: - event_args.update({"event_shape_type": shape.shape_type, "shape_size": shape.size}) + if do_rule_dict["action"]["type"] == "shape_action": + for shape in self.shapes: + 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}) + 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): + self.run_do_rule(key, 3, do_rule_dict, event_args) + + elif ruleset[1] == "or": + if self.check_rule(key, 1, if_rule_dicts[0], event_args) or self.check_rule(key, 2, if_rule_dicts[1], event_args): + self.run_do_rule(key, 3, do_rule_dict, event_args) + else: + event_args = trigger_args if ruleset[1] == "and": - if self.check_rule(key, 0, if_rule_dicts[0], event_args) and self.check_rule(key, 2, if_rule_dicts[1], event_args): + if self.check_rule(key, 1, if_rule_dicts[0], event_args) and self.check_rule(key, 2, if_rule_dicts[1], event_args): self.run_do_rule(key, 3, do_rule_dict, event_args) elif ruleset[1] == "or": - if self.check_rule(key, 0, if_rule_dicts[0], event_args) or self.check_rule(key, 2, if_rule_dicts[1], event_args): + if self.check_rule(key, 1, if_rule_dicts[0], event_args) or self.check_rule(key, 2, if_rule_dicts[1], event_args): self.run_do_rule(key, 3, do_rule_dict, event_args) for shape in self.shapes: - shape.update(self.gravity) + 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) 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] @@ -232,10 +344,29 @@ class Game(arcade.gui.UIView): description = rule_dict["description"].format_map(values) - self.rule_labels[f"{ruleset_num}_{rule_num}_desc"].text = description if rule_type == "if" else f"THEN {description}" + self.rule_labels[f"{ruleset_num}_{rule_num}_desc"].text = description self.rule_labels[key].text = f'{VAR_NAMES[n]}: {value}' - def on_draw(self): - super().on_draw() + def on_key_press(self, symbol, modifiers): + if symbol == arcade.key.ESCAPE: + self.main_exit() + elif symbol in ALLOWED_INPUT: + self.triggered_events.append(["on_input", {"event_key": chr(symbol)}]) - self.shape_batch.draw() \ No newline at end of file + def on_mouse_press(self, x, y, button, modifiers): + if button == arcade.MOUSE_BUTTON_LEFT: + self.triggered_events.append(["on_left_click", {}]) + elif button == arcade.MOUSE_BUTTON_RIGHT: + self.triggered_events.append(["on_right_click", {}]) + + def on_mouse_move(self, x, y, button, modifiers): + self.triggered_events.append(["on_mouse_move", {}]) + + def main_exit(self): + from menus.main import Main + self.window.show_view(Main(self.pypresence_client)) + + def on_draw(self): + self.window.clear() + self.shape_batch.draw() + self.ui.draw() \ No newline at end of file diff --git a/game/sprites.py b/game/sprites.py index 0e57c96..696be3f 100644 --- a/game/sprites.py +++ b/game/sprites.py @@ -1,4 +1,4 @@ -import pyglet +import pyglet, arcade.color from utils.constants import DEFAULT_X_VELOCITY, DEFAULT_Y_VELOCITY @@ -7,11 +7,22 @@ class BaseShape(): self.shape_type = "" self.x_velocity = DEFAULT_X_VELOCITY self.y_velocity = DEFAULT_Y_VELOCITY + self._shape_color = "WHITE" - def update(self, gravity): + def update(self, x_gravity, y_gravity): self.x += self.x_velocity self.y += self.y_velocity - self.y -= gravity + self.x -= x_gravity + self.y -= y_gravity + + @property + def shape_color(self): + return self._shape_color + + @shape_color.setter + def shape_color(self, color): + self._shape_color = color + self.color = getattr(arcade.color, color) class Circle(pyglet.shapes.Circle, BaseShape): def __init__(self, *args, **kwargs): @@ -41,4 +52,4 @@ class Triangle(pyglet.shapes.Triangle, BaseShape): @property def shape_size(self): - return self.x2 - self.x \ No newline at end of file + return max(self.x, self.x2, self.x3) - min(self.x, self.x2, self.x3) \ No newline at end of file diff --git a/utils/constants.py b/utils/constants.py index e802a41..f931dae 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -7,11 +7,27 @@ LOGICAL_OPERATORS = ["and", "or"] SHAPES = ["rectangle", "circle", "triangle"] VAR_NAMES = ["a", "b", "c", "d", "e", "f", "g"] -DEFAULT_GRAVITY = 2 +DEFAULT_X_GRAVITY = 0 +DEFAULT_Y_GRAVITY = 2 + DEFAULT_X_VELOCITY = 0 DEFAULT_Y_VELOCITY = 0 -COLORS = [key for key, value in arcade.color.__dict__.items() if isinstance(value, Color)] +ALLOWED_INPUT = [ord(key) for key in ["a", "b", "c", "d", "e", "q", "w", "s", "t"]] + +COLORS = [ + "BLACK", "WHITE", "GRAY", "DARK_GRAY", "CYAN", + "AMBER", "AQUA", "GREEN", "LIGHT_GREEN", + "RED", "LIGHT_RED", "DARK_RED", + "BLUE", "LIGHT_BLUE", "DARK_BLUE", + "YELLOW", "LIGHT_YELLOW", "DARK_YELLOW", + "MAGENTA", "PURPLE", "VIOLET", "INDIGO", + "ORANGE", "BROWN", + "GOLD", "SILVER", "BRONZE", + "TEAL", "AZURE", + "PINK", "HOT_PINK", + "MINT_GREEN", "CHARTREUSE" +] VAR_DEFAULT = { "shape_type": SHAPES[0], @@ -19,49 +35,94 @@ VAR_DEFAULT = { "variable": 0, "color": "WHITE", "size": 10, + "key_input": ALLOWED_INPUT[0] } VAR_OPTIONS = { "shape_type": SHAPES, "target_type": SHAPES, - "variable": (0, 2500), + "variable": (-700, 700), "color": COLORS, - "size": (1, 200), + "size": (1, 200), + "key_input": ALLOWED_INPUT } IF_RULES = { - "x_position": { - "key": "x_position", - "description": "IF X for {a} shape is {b}", + "x_position_greater": { + "key": "x_position_greater", + "description": "IF X for {a} shape is greater than {b}", "trigger": "every_update", "user_vars": ["shape_type", "variable"], "vars": ["shape_type", "variable", "event_shape_type", "shape_x"], - "func": lambda *v: (v[0] == v[2]) and (v[3] == v[1]) + "func": lambda *v: (v[0] == v[2]) and (v[3] > v[1]) }, - "y_position": { - "key": "y_position", - "description": "IF Y for {a} shape is {b}", + "x_position_less": { + "key": "x_position_less", + "description": "IF X for {a} shape is less than {b}", + "trigger": "every_update", + "user_vars": ["shape_type", "variable"], + "vars": ["shape_type", "variable", "event_shape_type", "shape_x"], + "func": lambda *v: (v[0] == v[2]) and (v[3] < v[1]) + }, + "x_position_between": { + "key": "x_position_between", + "description": "IF X for {a} shape is between {b} and {c}", + "trigger": "every_update", + "user_vars": ["shape_type", "variable", "variable"], + "vars": ["shape_type", "variable", "variable", "event_shape_type", "shape_x"], + "func": lambda *v: (v[0] == v[3]) and (min(v[1], v[2]) <= v[4] <= max(v[1], v[2])) + }, + + "y_position_greater": { + "key": "y_position_greater", + "description": "IF Y for {a} shape is greater than {b}", "trigger": "every_update", "user_vars": ["shape_type", "variable"], "vars": ["shape_type", "variable", "event_shape_type", "shape_y"], - "func": lambda *v: (v[0] == v[2]) and (v[3] == v[1]) + "func": lambda *v: (v[0] == v[2]) and (v[3] > v[1]) }, - "color_is": { - "key": "color_is", - "description": "IF {a} shape color is {b}", + "y_position_less": { + "key": "y_position_less", + "description": "IF Y for {a} shape is less than {b}", "trigger": "every_update", - "user_vars": ["shape_type", "color"], - "vars": ["shape_type", "color", "event_shape_type", "shape_color"], - "func": lambda *v: (v[0] == v[2]) and (v[3] == v[1]) + "user_vars": ["shape_type", "variable"], + "vars": ["shape_type", "variable", "event_shape_type", "shape_y"], + "func": lambda *v: (v[0] == v[2]) and (v[3] < v[1]) }, - "size_is": { - "key": "size_is", - "description": "IF {a} shape size is {b}", + "y_position_between": { + "key": "y_position_between", + "description": "IF Y for {a} shape is between {b} and {c}", "trigger": "every_update", - "user_vars": ["shape_type", "size"], - "vars": ["shape_type", "size", "event_shape_type", "shape_size"], - "func": lambda *v: (v[0] == v[2]) and (v[3] == v[1]) + "user_vars": ["shape_type", "variable", "variable"], + "vars": ["shape_type", "variable", "variable", "event_shape_type", "shape_y"], + "func": lambda *v: (v[0] == v[3]) and (min(v[1], v[2]) <= v[4] <= max(v[1], v[2])) }, + + "size_greater": { + "key": "size_greater", + "description": "IF {a} shape size is greater than {b}", + "trigger": "every_update", + "user_vars": ["shape_type", "variable"], + "vars": ["shape_type", "variable", "event_shape_type", "shape_size"], + "func": lambda *v: (v[0] == v[2]) and (v[3] > v[1]) + }, + "size_less": { + "key": "size_less", + "description": "IF {a} shape size is less than {b}", + "trigger": "every_update", + "user_vars": ["shape_type", "variable"], + "vars": ["shape_type", "variable", "event_shape_type", "shape_size"], + "func": lambda *v: (v[0] == v[2]) and (v[3] < v[1]) + }, + "size_between": { + "key": "size_between", + "description": "IF {a} shape size is between {b} and {c}", + "trigger": "every_update", + "user_vars": ["shape_type", "variable", "variable"], + "vars": ["shape_type", "variable", "variable", "event_shape_type", "shape_size"], + "func": lambda *v: (v[0] == v[3]) and (min(v[1], v[2]) <= v[4] <= max(v[1], v[2])) + }, + "spawns": { "key": "spawns", "description": "IF {a} shape spawns", @@ -81,7 +142,7 @@ IF_RULES = { "x_velocity_changes": { "key": "x_velocity_changes", "description": "IF {a} shape X velocity changes", - "trigger": "x_change", + "trigger": "x_velocity_change", "user_vars": ["shape_type"], "vars": ["shape_type", "event_shape_type"], "func": lambda *v: v[0] == v[1] @@ -89,7 +150,7 @@ IF_RULES = { "y_velocity_changes": { "key": "y_velocity_changes", "description": "IF {a} shape Y velocity changes", - "trigger": "y_change", + "trigger": "y_velocity_change", "user_vars": ["shape_type"], "vars": ["shape_type", "event_shape_type"], "func": lambda *v: v[0] == v[1] @@ -110,14 +171,6 @@ IF_RULES = { "vars": ["shape_type", "event_shape_type"], "func": lambda *v: v[0] == v[1] }, - "gravity_changes": { - "key": "gravity_changes", - "description": "IF gravity changes", - "user_vars": [], - "trigger": "gravity_change", - "vars": [], - "func": lambda *v: True - }, "color_changes": { "key": "color_changes", "description": "IF {a} shape color changes", @@ -150,6 +203,38 @@ IF_RULES = { "vars": ["shape_type", "target_type", "event_a_type", "event_b_type"], "func": lambda *v: (v[0] == v[2]) and (v[3] == v[1]) }, + "on_left_click": { + "key": "on_left_click", + "description": "IF you left click", + "trigger": "on_left_click", + "user_vars": [], + "vars": [], + "func": lambda *v: True + }, + "on_right_click": { + "key": "on_right_click", + "description": "IF you right click", + "trigger": "on_right_click", + "user_vars": [], + "vars": [], + "func": lambda *v: True + }, + "on_mouse_move": { + "key": "on_mouse_move", + "description": "IF mouse moves", + "trigger": "on_mouse_move", + "user_vars": [], + "vars": [], + "func": lambda *v: True + }, + "on_input": { + "key": "on_input", + "description": "IF {a} key is pressed", + "trigger": "on_input", + "user_vars": ["key_input"], + "vars": ["key_input", "event_key"], + "func": lambda *v: v[0] == v[1] + }, "game_launch": { "key": "game_launch", "description": "IF game launches", @@ -176,39 +261,29 @@ NON_COMPATIBLE_WHEN = [ ("spawns", "y_velocity_changes"), ("spawns", "x_gravity_changes"), ("spawns", "y_gravity_changes"), - ("spawns", "gravity_changes"), ("spawns", "color_changes"), ("spawns", "size_changes"), - + ("destroyed", "morphs"), ("destroyed", "collides"), ("destroyed", "x_velocity_changes"), ("destroyed", "y_velocity_changes"), ("destroyed", "x_gravity_changes"), ("destroyed", "y_gravity_changes"), - ("destroyed", "gravity_changes"), ("destroyed", "color_changes"), ("destroyed", "size_changes"), - + ("morphs", "collides"), ("morphs", "x_velocity_changes"), ("morphs", "y_velocity_changes"), ("morphs", "x_gravity_changes"), ("morphs", "y_gravity_changes"), - ("morphs", "gravity_changes"), ("morphs", "color_changes"), ("morphs", "size_changes"), - + ("collides", "destroyed"), ("collides", "morphs"), - ("collides", "gravity_changes"), - - ("x_gravity_changes", "gravity_changes"), - ("y_gravity_changes", "gravity_changes"), - - ("color_changes", "gravity_changes"), - ("size_changes", "gravity_changes"), - + ("every_update", "spawns"), ("every_update", "destroyed"), ("every_update", "morphs"), @@ -217,22 +292,20 @@ NON_COMPATIBLE_WHEN = [ ("every_update", "y_velocity_changes"), ("every_update", "x_gravity_changes"), ("every_update", "y_gravity_changes"), - ("every_update", "gravity_changes"), ("every_update", "color_changes"), ("every_update", "size_changes"), - ("every_update", "launch"), - - ("launch", "spawns"), - ("launch", "destroyed"), - ("launch", "morphs"), - ("launch", "collides"), - ("launch", "x_velocity_changes"), - ("launch", "y_velocity_changes"), - ("launch", "x_gravity_changes"), - ("launch", "y_gravity_changes"), - ("launch", "gravity_changes"), - ("launch", "color_changes"), - ("launch", "size_changes"), + ("every_update", "game_launch"), + + ("game_launch", "spawns"), + ("game_launch", "destroyed"), + ("game_launch", "morphs"), + ("game_launch", "collides"), + ("game_launch", "x_velocity_changes"), + ("game_launch", "y_velocity_changes"), + ("game_launch", "x_gravity_changes"), + ("game_launch", "y_gravity_changes"), + ("game_launch", "color_changes"), + ("game_launch", "size_changes"), ] NON_COMPATIBLE_DO_WHEN = [ @@ -242,43 +315,45 @@ NON_COMPATIBLE_DO_WHEN = [ ("destroyed", "move_y"), ("destroyed", "change_x_velocity"), ("destroyed", "change_y_velocity"), - ("destroyed", "change_gravity"), + ("destroyed", "change_x_gravity"), + ("destroyed", "change_y_gravity"), ("destroyed", "change_color"), ("destroyed", "change_size"), ("destroyed", "morph_into"), ("destroyed", "destroy"), - + ("morphs", "morph_into"), - - ("gravity_changes", "change_x"), - ("gravity_changes", "change_y"), - ("gravity_changes", "move_x"), - ("gravity_changes", "move_y"), - ("gravity_changes", "change_x_velocity"), - ("gravity_changes", "change_y_velocity"), - ("gravity_changes", "change_gravity"), - ("gravity_changes", "change_color"), - ("gravity_changes", "change_size"), - ("gravity_changes", "morph_into"), - ("gravity_changes", "destroy"), - + ("x_velocity_changes", "change_x_velocity"), ("y_velocity_changes", "change_y_velocity"), ("color_changes", "change_color"), + ("size_changes", "change_size"), - - ("launch", "change_x"), - ("launch", "change_y"), - ("launch", "move_x"), - ("launch", "move_y"), - ("launch", "change_x_velocity"), - ("launch", "change_y_velocity"), - ("launch", "change_gravity"), - ("launch", "change_color"), - ("launch", "change_size"), - ("launch", "destroy"), - ("launch", "morph_into") + + ("every_update", "change_x"), + ("every_update", "change_y"), + ("every_update", "move_x"), + ("every_update", "move_y"), + ("every_update", "change_x_velocity"), + ("every_update", "change_y_velocity"), + ("every_update", "change_color"), + ("every_update", "change_size"), + ("every_update", "destroy"), + ("every_update", "morph_into"), + + ("game_launch", "change_x"), + ("game_launch", "change_y"), + ("game_launch", "move_x"), + ("game_launch", "move_y"), + ("game_launch", "change_x_velocity"), + ("game_launch", "change_y_velocity"), + ("game_launch", "change_x_gravity"), + ("game_launch", "change_y_gravity"), + ("game_launch", "change_color"), + ("game_launch", "change_size"), + ("game_launch", "destroy"), + ("game_launch", "morph_into") ] DO_RULES = { @@ -286,84 +361,104 @@ DO_RULES = { "key": "change_x", "description": "Change this shape's X to {a}", "action": {"type": "shape_action", "name": "change_x"}, - "user_vars": ["shape", "variable"] + "user_vars": ["variable"], + "vars": ["shape", "variable"] }, "change_y": { "key": "change_y", "description": "Change this shape's Y to {a}", "action": {"type": "shape_action", "name": "change_y"}, - "user_vars": ["shape", "variable"] + "user_vars": ["variable"], + "vars": ["shape", "variable"] }, "move_x": { "key": "move_x", "description": "Move this shape's X by {a}", "action": {"type": "shape_action", "name": "move_x"}, - "user_vars": ["shape", "variable"] + "user_vars": ["variable"], + "vars": ["shape", "variable"] }, "move_y": { "key": "move_y", "description": "Move this shape's Y by {a}", "action": {"type": "shape_action", "name": "move_y"}, - "user_vars": ["shape", "variable"] + "user_vars": ["variable"], + "vars": ["shape", "variable"] }, "change_x_velocity": { "key": "change_x_velocity", "description": "Change X velocity of this to {a}", - "action": {"type": "shape_action", "name": "change_x_vel"}, - "user_vars": ["shape", "variable"] + "action": {"type": "shape_action", "name": "change_x_velocity"}, + "user_vars": ["variable"], + "vars": ["shape", "variable"] }, "change_y_velocity": { "key": "change_y_velocity", "description": "Change Y velocity of this to {a}", - "action": {"type": "shape_action", "name": "change_y_vel"}, - "user_vars": ["shape", "variable"] + "action": {"type": "shape_action", "name": "change_y_velocity"}, + "user_vars": ["variable"], + "vars": ["shape", "variable"] }, "change_color": { "key": "change_color", "description": "Change this shape's color to {a}", "action": {"type": "shape_action", "name": "change_color"}, - "user_vars": ["shape", "color"] + "user_vars": ["color"], + "vars": ["shape", "color"] }, "change_size": { "key": "change_size", "description": "Change this shape's size to {a}", "action": {"type": "shape_action", "name": "change_size"}, - "user_vars": ["shape", "size"] + "user_vars": ["size"], + "vars": ["shape", "size"] }, "destroy": { "key": "destroy", "description": "Destroy this", "action": {"type": "shape_action", "name": "destroy"}, - "user_vars": ["shape"] + "user_vars": [], + "vars": ["shape"] }, "morph_into": { "key": "morph_into", "description": "Morph this into {a}", "action": {"type": "shape_action", "name": "morph"}, - "user_vars": ["shape", "shape_type"] + "user_vars": ["shape_type"], + "vars": ["shape", "shape_type"] }, - "change_gravity": { - "key": "change_gravity", - "description": "Change gravity to {a}", - "action": {"type": "global_action", "name": "change_gravity"}, - "user_vars": ["shape", "variable"] + "change_x_gravity": { + "key": "change_x_gravity", + "description": "Change X gravity to {a}", + "action": {"type": "global_action", "name": "change_x_gravity"}, + "user_vars": ["variable"], + "vars": ["variable"] + }, + + "change_y_gravity": { + "key": "change_y_gravity", + "description": "Change Y gravity to {a}", + "action": {"type": "global_action", "name": "change_y_gravity"}, + "user_vars": ["variable"], + "vars": ["variable"] }, "spawn": { "key": "spawn", "description": "Spawn {a}", "action": {"type": "global_action", "name": "spawn"}, - "user_vars": ["shape_type"] + "user_vars": ["shape_type"], + "vars": ["shape_type"] } } diff --git a/utils/preload.py b/utils/preload.py index fcd2cf3..616c84d 100644 --- a/utils/preload.py +++ b/utils/preload.py @@ -5,4 +5,10 @@ _module_dir = os.path.dirname(os.path.abspath(__file__)) _assets_dir = os.path.join(os.path.dirname(_module_dir), 'assets') button_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'button.png'))) -button_hovered_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'button_hovered.png'))) \ No newline at end of file +button_hovered_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'button_hovered.png'))) + +SPRITE_TEXTURES = { + "circle": arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'sprites', 'circle.png')), + "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')), +} diff --git a/utils/utils.py b/utils/utils.py index 470037e..746040f 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,9 +1,7 @@ -import logging, arcade, arcade.gui, sys, traceback +import logging, arcade, arcade.gui, sys, traceback, pyglet.display from utils.constants import menu_background_color -import pyglet.info, pyglet.event - def dump_platform(): import platform logging.debug(f'Platform: {platform.platform()}') @@ -16,6 +14,7 @@ def dump_gl(context=None): info = context.get_info() else: from pyglet.gl import gl_info as info + logging.debug(f'gl_info.get_version(): {info.get_version()}') logging.debug(f'gl_info.get_vendor(): {info.get_vendor()}') logging.debug(f'gl_info.get_renderer(): {info.get_renderer()}') @@ -37,30 +36,7 @@ def print_debug_info(): logging.debug('') logging.debug('########################## DEBUG INFO ##########################') logging.debug('') - -class ErrorView(arcade.gui.UIView): - def __init__(self, message, title): - super().__init__() - - self.message = message - self.title = title - - def exit(self): - logging.fatal('Exited with error code 1.') - sys.exit(1) - - def on_show_view(self): - super().on_show_view() - - self.window.set_caption('Chaos Protocol - Error') - self.window.set_mouse_visible(True) - self.window.set_exclusive_mouse(False) - arcade.set_background_color(menu_background_color) - - msgbox = arcade.gui.UIMessageBox(width=self.window.width / 2, height=self.window.height / 2, message_text=self.message, title=self.title) - msgbox.on_action = lambda _: self.exit() - self.add_widget(msgbox) - + def on_exception(*exc_info): logging.error(f"Unhandled exception:\n{''.join(traceback.format_exception(exc_info[1], limit=None))}")