use ruleset instead of rule for naming, make rules editable by rebuilding the rulesets, make rule button have simple and advanced rule options, fix key input, fix mouse motion input

This commit is contained in:
csd4ni3l
2025-11-23 23:41:14 +01:00
parent d5de17f8e0
commit 6a318ebe67
3 changed files with 99 additions and 21 deletions

View File

@@ -5,7 +5,7 @@ from utils.constants import slider_style, dropdown_style, VAR_NAMES, VAR_DEFAULT
from arcade.gui.experimental.scroll_area import UIScrollArea, UIScrollBar from arcade.gui.experimental.scroll_area import UIScrollArea, UIScrollBar
from game.rules import generate_rule from game.rules import generate_ruleset
from game.sprites import BaseShape, Rectangle, Circle, Triangle from game.sprites import BaseShape, Rectangle, Circle, Triangle
class Game(arcade.gui.UIView): class Game(arcade.gui.UIView):
@@ -17,7 +17,7 @@ class Game(arcade.gui.UIView):
self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1))) self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1)))
self.scroll_area = UIScrollArea(size_hint=(0.25, 1)) # center on screen self.scroll_area = UIScrollArea(size_hint=(0.25, 1))
self.scroll_area.scroll_speed = -75 self.scroll_area.scroll_speed = -75
self.anchor.add(self.scroll_area, anchor_x="right", anchor_y="bottom", 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)
@@ -40,6 +40,7 @@ class Game(arcade.gui.UIView):
self.rule_labels = {} self.rule_labels = {}
self.rule_var_changers = {} self.rule_var_changers = {}
self.rule_boxes = {}
self.shapes = [] self.shapes = []
self.shape_batch = pyglet.graphics.Batch() self.shape_batch = pyglet.graphics.Batch()
@@ -157,15 +158,32 @@ class Game(arcade.gui.UIView):
elif a == "triangle": 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)) 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 get_rule_defaults(self, rule_type):
if rule_type == "if":
return {
rule_key: (
rule_dict["description"].format_map({VAR_NAMES[n]: VAR_DEFAULT[variable] for n, variable in enumerate(rule_dict["user_vars"])}),
{VAR_NAMES[n]: VAR_DEFAULT[variable] for n, variable in enumerate(rule_dict["user_vars"])}
)
for rule_key, rule_dict in IF_RULES.items()
}
elif rule_type == "do":
return {
rule_key: (
rule_dict["description"].format_map({VAR_NAMES[n]: VAR_DEFAULT[variable] for n, variable in enumerate(rule_dict["user_vars"])}),
{VAR_NAMES[n]: VAR_DEFAULT[variable] for n, variable in enumerate(rule_dict["user_vars"])}
)
for rule_key, rule_dict in DO_RULES.items()
}
def create_rule_ui(self, rule_box: arcade.gui.UIBoxLayout, rule, rule_type, rule_num=1): def create_rule_ui(self, rule_box: arcade.gui.UIBoxLayout, rule, rule_type, rule_num=1):
defaults = self.get_rule_defaults(rule_type)
rule_dict = IF_RULES[rule] if rule_type == "if" else DO_RULES[rule] rule_dict = IF_RULES[rule] if rule_type == "if" else DO_RULES[rule]
ruleset_num = self.current_ruleset_num ruleset_num = self.current_ruleset_num
default_values = defaults[rule][1]
default_values = {VAR_NAMES[n]: VAR_DEFAULT[variable] for n, variable in enumerate(rule_dict["user_vars"])} dropdown_options = [desc for desc, _ in defaults.values()]
description = rule_dict["description"].format_map(default_values) desc_label = rule_box.add(arcade.gui.UIDropdown(default=defaults[rule][0], options=dropdown_options, font_size=13, width=self.window.width * 0.225, active_style=dropdown_style, primary_style=dropdown_style, dropdown_style=dropdown_style))
desc_label.on_change = lambda event, rule_type=rule_type, ruleset_num=ruleset_num, rule_num=rule_num: self.change_rule_type(ruleset_num, rule_num, rule_type, event.new_value)
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 self.rule_labels[f"{self.current_ruleset_num}_{rule_num}_desc"] = desc_label
for n, variable_type in enumerate(rule_dict["user_vars"]): for n, variable_type in enumerate(rule_dict["user_vars"]):
@@ -182,13 +200,68 @@ class Game(arcade.gui.UIView):
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) 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 self.rule_var_changers[key] = slider
elif variable_type in ["shape_type", "target_type", "color"]: elif variable_type in ["shape_type", "target_type", "color", "key_input"]:
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 = 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) 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 self.rule_var_changers[key] = dropdown
def change_rule_type(self, ruleset_num, rule_num, rule_type, new_rule_text):
defaults = self.get_rule_defaults(rule_type)
new_rule_name = next(key for key, default_list in defaults.items() if default_list[0] == new_rule_text)
ruleset = self.rulesets[ruleset_num]
if len(ruleset) == 2:
if rule_type == "if":
ruleset[0] = new_rule_name
else:
ruleset[1] = new_rule_name
else:
if rule_type == "if":
if rule_num == 1:
ruleset[0] = new_rule_name
else:
ruleset[2] = new_rule_name
else:
ruleset[3] = new_rule_name
self.rebuild_ruleset_ui(ruleset_num)
def rebuild_ruleset_ui(self, ruleset_num):
rule_box = self.rule_boxes[ruleset_num]
keys_to_remove = [k for k in self.rule_labels.keys() if k.startswith(f"{ruleset_num}_")]
for key in keys_to_remove:
del self.rule_labels[key]
keys_to_remove = [k for k in self.rule_var_changers.keys() if k.startswith(f"{ruleset_num}_")]
for key in keys_to_remove:
del self.rule_var_changers[key]
keys_to_remove = [k for k in self.rule_values.keys() if k.startswith(f"{ruleset_num}_")]
for key in keys_to_remove:
del self.rule_values[key]
rule_box.clear()
ruleset = self.rulesets[ruleset_num]
old_ruleset_num = self.current_ruleset_num
self.current_ruleset_num = ruleset_num
if len(ruleset) == 2:
self.create_rule_ui(rule_box, ruleset[0], "if")
self.create_rule_ui(rule_box, ruleset[1], "do", 2)
else:
self.create_rule_ui(rule_box, ruleset[0], "if")
rule_box.add(arcade.gui.UILabel(ruleset[1].upper(), font_size=14, width=self.window.width * 0.25))
self.create_rule_ui(rule_box, ruleset[2], "if", 2)
self.create_rule_ui(rule_box, ruleset[3], "do", 3)
self.current_ruleset_num = old_ruleset_num
def add_ruleset(self, ruleset): def add_ruleset(self, ruleset):
rule_box = self.rules_box.add(arcade.gui.UIBoxLayout(space_between=5, align="left").with_background(color=arcade.color.DARK_SLATE_GRAY)) rule_box = self.rules_box.add(arcade.gui.UIBoxLayout(space_between=5, align="left").with_background(color=arcade.color.DARK_SLATE_GRAY))
self.rule_boxes[self.current_ruleset_num] = rule_box
if len(ruleset) == 2: if len(ruleset) == 2:
self.rulesets[self.current_ruleset_num] = ruleset self.rulesets[self.current_ruleset_num] = ruleset
@@ -210,27 +283,32 @@ class Game(arcade.gui.UIView):
super().on_show_view() super().on_show_view()
self.rules_box.add(arcade.gui.UILabel(text="Rules", font_size=24, text_color=arcade.color.BLACK)) 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 self.rules_box.add(arcade.gui.UISpace(height=self.window.height / 50, width=self.window.width * 0.25))
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_simple_rule_button = self.rules_box.add(arcade.gui.UIFlatButton(text="Add Simple 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() add_simple_rule_button.on_click = lambda event: self.add_rule("simple")
self.rules_box.add(arcade.gui.UISpace(height=self.window.height / 75))
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 / 15, 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 / 50)) self.rules_box.add(arcade.gui.UISpace(height=self.window.height / 50))
self.add_rule(["on_left_click", "spawn"]) self.add_rule(None, ["on_left_click", "spawn"])
self.add_rule(["size_greater", "morph_into"]) self.add_rule(None, ["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.UILabel(text="Sprites", font_size=24, text_color=arcade.color.BLACK))
self.sprites_box.add(arcade.gui.UISpace(height=self.window.height / 50)) self.sprites_box.add(arcade.gui.UISpace(height=self.window.height / 50))
for shape in SHAPES: for shape in SHAPES:
self.sprites_box.add(arcade.gui.UILabel(text=shape, font_size=16)) 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.UIImage(texture=SPRITE_TEXTURES[shape], width=self.window.width / 15, height=self.window.width / 15))
self.triggered_events.append(["game_launch", {}]) self.triggered_events.append(["game_launch", {}])
def add_rule(self, force=None): def add_rule(self, ruleset_type=None, force=None):
self.rulesets[self.current_ruleset_num] = generate_rule() if not force else force self.rulesets[self.current_ruleset_num] = generate_ruleset(ruleset_type) if not force else force
self.add_ruleset(self.rulesets[self.current_ruleset_num]) self.add_ruleset(self.rulesets[self.current_ruleset_num])
self.current_ruleset_num += 1 self.current_ruleset_num += 1
@@ -350,7 +428,7 @@ class Game(arcade.gui.UIView):
def on_key_press(self, symbol, modifiers): def on_key_press(self, symbol, modifiers):
if symbol == arcade.key.ESCAPE: if symbol == arcade.key.ESCAPE:
self.main_exit() self.main_exit()
elif symbol in ALLOWED_INPUT: elif symbol in [ord(key) for key in ALLOWED_INPUT]:
self.triggered_events.append(["on_input", {"event_key": chr(symbol)}]) self.triggered_events.append(["on_input", {"event_key": chr(symbol)}])
def on_mouse_press(self, x, y, button, modifiers): def on_mouse_press(self, x, y, button, modifiers):
@@ -359,7 +437,7 @@ class Game(arcade.gui.UIView):
elif button == arcade.MOUSE_BUTTON_RIGHT: elif button == arcade.MOUSE_BUTTON_RIGHT:
self.triggered_events.append(["on_right_click", {}]) self.triggered_events.append(["on_right_click", {}])
def on_mouse_move(self, x, y, button, modifiers): def on_mouse_motion(self, x, y, button, modifiers):
self.triggered_events.append(["on_mouse_move", {}]) self.triggered_events.append(["on_mouse_move", {}])
def main_exit(self): def main_exit(self):

View File

@@ -8,10 +8,10 @@ DO_KEYS = tuple(DO_RULES.keys())
BAD_WHEN = {tuple(sorted(pair)) for pair in NON_COMPATIBLE_WHEN} BAD_WHEN = {tuple(sorted(pair)) for pair in NON_COMPATIBLE_WHEN}
BAD_DO_WHEN = {tuple(pair) for pair in NON_COMPATIBLE_DO_WHEN} BAD_DO_WHEN = {tuple(pair) for pair in NON_COMPATIBLE_DO_WHEN}
def generate_rule(): def generate_ruleset(ruleset_type):
when_a = random.choice(IF_KEYS) when_a = random.choice(IF_KEYS)
if random.random() < 0.5: if ruleset_type == "advanced":
valid_b = [ valid_b = [
b for b in IF_KEYS b for b in IF_KEYS
if b != when_a and tuple(sorted((when_a, b))) not in BAD_WHEN if b != when_a and tuple(sorted((when_a, b))) not in BAD_WHEN

View File

@@ -13,7 +13,7 @@ DEFAULT_Y_GRAVITY = 2
DEFAULT_X_VELOCITY = 0 DEFAULT_X_VELOCITY = 0
DEFAULT_Y_VELOCITY = 0 DEFAULT_Y_VELOCITY = 0
ALLOWED_INPUT = [ord(key) for key in ["a", "b", "c", "d", "e", "q", "w", "s", "t"]] ALLOWED_INPUT = ["a", "b", "c", "d", "e", "q", "w", "s", "t"]
COLORS = [ COLORS = [
"BLACK", "WHITE", "GRAY", "DARK_GRAY", "CYAN", "BLACK", "WHITE", "GRAY", "DARK_GRAY", "CYAN",