mirror of
https://github.com/csd4ni3l/simulator-games.git
synced 2026-01-01 04:13:44 +01:00
Added water splash simulator, made settings saving work for all simulators, moved all the simulators into their respective directories, improved the README, fixed too much logging
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -180,3 +180,4 @@ test*.py
|
|||||||
logs/
|
logs/
|
||||||
logs
|
logs
|
||||||
settings.json
|
settings.json
|
||||||
|
data.json
|
||||||
@@ -1 +1,5 @@
|
|||||||
Some simulator games i tried to make to get better at math and interesting concepts. Currently includes a Boids simulator and a Physics Sandbox
|
Some simulator games i tried to make to get better at math and interesting concepts. Currently includes a Boids simulator, Water Simulator and a Physics Sandbox
|
||||||
|
|
||||||
|
The Water Simulator simulates 2d water splashes.
|
||||||
|
The Physics Sandbox includes crates, coins, and any custom SVG you want! Use w to place the current inventory item, and on the right bottom you can select new ones.
|
||||||
|
The boids simulator simulates how birds move together and you can change the weights so they move in a certain direction!
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 264 B |
@@ -1,6 +1,6 @@
|
|||||||
import arcade, arcade.gui, random
|
import arcade, arcade.gui, random, os, json
|
||||||
|
|
||||||
from game.boid import Boid
|
from game.boid_simulator.boid import Boid
|
||||||
|
|
||||||
class Game(arcade.gui.UIView):
|
class Game(arcade.gui.UIView):
|
||||||
def __init__(self, pypresence_client):
|
def __init__(self, pypresence_client):
|
||||||
@@ -11,6 +11,21 @@ class Game(arcade.gui.UIView):
|
|||||||
self.boid_sprites = arcade.SpriteList()
|
self.boid_sprites = arcade.SpriteList()
|
||||||
self.current_boid_num = 1
|
self.current_boid_num = 1
|
||||||
|
|
||||||
|
if os.path.exists("data.json"):
|
||||||
|
with open("data.json", "r") as file:
|
||||||
|
self.settings = json.load(file)
|
||||||
|
else:
|
||||||
|
self.settings = {}
|
||||||
|
|
||||||
|
if not "boid_simulator" in self.settings:
|
||||||
|
self.settings["boid_simulator"] = {
|
||||||
|
"w_separation": 1.0,
|
||||||
|
"w_alignment": 1.0,
|
||||||
|
"w_cohesion": 1.0,
|
||||||
|
"small_radius": 100,
|
||||||
|
"large_radius": 250
|
||||||
|
}
|
||||||
|
|
||||||
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.settings_box = self.anchor.add(arcade.gui.UIBoxLayout(space_between=5, align="center", size_hint=(0.2, 1)).with_background(color=arcade.color.GRAY), anchor_x="right", anchor_y="bottom")
|
self.settings_box = self.anchor.add(arcade.gui.UIBoxLayout(space_between=5, align="center", size_hint=(0.2, 1)).with_background(color=arcade.color.GRAY), anchor_x="right", anchor_y="bottom")
|
||||||
@@ -18,12 +33,16 @@ class Game(arcade.gui.UIView):
|
|||||||
self.add_setting("Separation Weight: {value}", 0.1, 5, 0.1, "w_separation")
|
self.add_setting("Separation Weight: {value}", 0.1, 5, 0.1, "w_separation")
|
||||||
self.add_setting("Alignment Weight: {value}", 0.1, 5, 0.1, "w_alignment")
|
self.add_setting("Alignment Weight: {value}", 0.1, 5, 0.1, "w_alignment")
|
||||||
self.add_setting("Cohesion Weight: {value}", 0.1, 5, 0.1, "w_cohesion")
|
self.add_setting("Cohesion Weight: {value}", 0.1, 5, 0.1, "w_cohesion")
|
||||||
self.add_setting("Small Radius: {value}", 25, 250, 25, "small_radius", 100)
|
self.add_setting("Small Radius: {value}", 25, 250, 25, "small_radius")
|
||||||
self.add_setting("Large Radius: {value}", 50, 500, 50, "large_radius", 250)
|
self.add_setting("Large Radius: {value}", 50, 500, 50, "large_radius")
|
||||||
|
|
||||||
def add_setting(self, text, min_value, max_value, step, boid_variable, default=None):
|
def save_data(self):
|
||||||
label = self.settings_box.add(arcade.gui.UILabel(text.format(value=default or 1.0)))
|
with open("data.json", "w") as file:
|
||||||
slider = self.settings_box.add(arcade.gui.UISlider(value=1.0, min_value=min_value, max_value=max_value, step=step, size_hint=(1, 0.05)))
|
file.write(json.dumps(self.settings, indent=4))
|
||||||
|
|
||||||
|
def add_setting(self, text, min_value, max_value, step, boid_variable):
|
||||||
|
label = self.settings_box.add(arcade.gui.UILabel(text.format(value=self.settings["boid_simulator"][boid_variable])))
|
||||||
|
slider = self.settings_box.add(arcade.gui.UISlider(value=self.settings["boid_simulator"][boid_variable], min_value=min_value, max_value=max_value, step=step, size_hint=(1, 0.05)))
|
||||||
slider._render_steps = lambda surface: None
|
slider._render_steps = lambda surface: None
|
||||||
|
|
||||||
slider.on_change = lambda event, label=label: self.change_value(label, text, boid_variable, event.new_value)
|
slider.on_change = lambda event, label=label: self.change_value(label, text, boid_variable, event.new_value)
|
||||||
@@ -31,6 +50,8 @@ class Game(arcade.gui.UIView):
|
|||||||
def change_value(self, label, text, boid_variable, value):
|
def change_value(self, label, text, boid_variable, value):
|
||||||
label.text = text.format(value=value)
|
label.text = text.format(value=value)
|
||||||
|
|
||||||
|
self.settings["boid_simulator"][boid_variable] = value
|
||||||
|
|
||||||
for boid in self.boid_sprites:
|
for boid in self.boid_sprites:
|
||||||
setattr(boid, boid_variable, value)
|
setattr(boid, boid_variable, value)
|
||||||
|
|
||||||
@@ -57,6 +78,8 @@ 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.save_data()
|
||||||
|
|
||||||
from menus.main import Main
|
from menus.main import Main
|
||||||
self.window.show_view(Main(self.pypresence_client))
|
self.window.show_view(Main(self.pypresence_client))
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ class BodyInventory(arcade.gui.UIGridLayout):
|
|||||||
|
|
||||||
n = 0
|
n = 0
|
||||||
for name, image in items.items():
|
for name, image in items.items():
|
||||||
self.buttons[name] = self.add(arcade.gui.UITextureButton(width=(window_width * 0.2) / 4, height=(window_width * 0.2) / 4).with_background(texture=arcade.load_texture(image), color=arcade.color.WHITE if name == self.selected_item else arcade.color.TRANSPARENT_BLACK), column=n % 2, row=n // 2)
|
self.buttons[name] = self.add(arcade.gui.UITextureButton(width=(window_width * 0.2) / 4, height=(window_width * 0.2) / 4).with_background(texture=arcade.load_texture(image), color=arcade.color.WHITE if name == self.selected_item else arcade.color.TRANSPARENT_BLACK).with_border(color=arcade.color.WHITE), column=n % 2, row=n // 2)
|
||||||
self.buttons[name].on_click = lambda event, name=name: self.change_to(name)
|
self.buttons[name].on_click = lambda event, name=name: self.change_to(name)
|
||||||
|
|
||||||
n += 1
|
n += 1
|
||||||
@@ -22,11 +22,11 @@ class BodyInventory(arcade.gui.UIGridLayout):
|
|||||||
|
|
||||||
self._update_size_hints()
|
self._update_size_hints()
|
||||||
|
|
||||||
self.items[name] = image
|
self.buttons[name] = self.add(arcade.gui.UITextureButton(width=(self.window_width * 0.2) / 4, height=(self.window_width * 0.2) / 4, color=arcade.color.TRANSPARENT_BLACK).with_background(texture=image).with_border(color=arcade.color.WHITE), column=len(self.items) % 2, row=len(self.items) // 2)
|
||||||
|
|
||||||
self.buttons[name] = self.add(arcade.gui.UITextureButton(width=(self.window_width * 0.2) / 2, height=(self.window_height * 0.1) / math.ceil(len(self.items) / 2), color=arcade.color.TRANSPARENT_BLACK).with_background(texture=image), column=len(self.items) % 2, row=len(self.items) // 2)
|
|
||||||
self.buttons[name].on_click = lambda event, name=name: self.change_to(name)
|
self.buttons[name].on_click = lambda event, name=name: self.change_to(name)
|
||||||
|
|
||||||
|
self.items[name] = image
|
||||||
|
|
||||||
def change_to(self, name):
|
def change_to(self, name):
|
||||||
self.buttons[self.selected_item] = self.buttons[self.selected_item].with_background(color=arcade.color.TRANSPARENT_BLACK)
|
self.buttons[self.selected_item] = self.buttons[self.selected_item].with_background(color=arcade.color.TRANSPARENT_BLACK)
|
||||||
self.selected_item = name
|
self.selected_item = name
|
||||||
@@ -1,22 +1,31 @@
|
|||||||
import arcade, arcade.gui, pymunk, pymunk.util, math, time, os, io, cairosvg
|
import arcade, arcade.gui, pymunk, pymunk.util, math, time, os, io, cairosvg, json, random
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from arcade.gui.experimental.scroll_area import UIScrollArea, UIScrollBar
|
from arcade.gui.experimental.scroll_area import UIScrollArea, UIScrollBar
|
||||||
|
|
||||||
|
from pymunk.autogeometry import convex_decomposition
|
||||||
|
|
||||||
from svgpathtools import svg2paths
|
from svgpathtools import svg2paths
|
||||||
from game.body_inventory import BodyInventory
|
|
||||||
|
from game.physics_playground.body_inventory import BodyInventory
|
||||||
|
|
||||||
from utils.constants import menu_background_color, button_style
|
from utils.constants import menu_background_color, button_style
|
||||||
from utils.preload import button_texture, button_hovered_texture
|
from utils.preload import button_texture, button_hovered_texture
|
||||||
|
|
||||||
|
class FakeShape():
|
||||||
|
def __init__(self, body):
|
||||||
|
self.body = body
|
||||||
|
|
||||||
|
class CustomPhysics(arcade.Sprite):
|
||||||
|
def __init__(self, pymunk_obj, filename):
|
||||||
|
super().__init__(filename, center_x=pymunk_obj.body.position.x, center_y=pymunk_obj.body.position.y)
|
||||||
|
self.pymunk_obj = pymunk_obj
|
||||||
|
|
||||||
class SpritePhysics(arcade.Sprite):
|
class SpritePhysics(arcade.Sprite):
|
||||||
def __init__(self, pymunk_obj, filename):
|
def __init__(self, pymunk_obj, filename):
|
||||||
super().__init__(filename, center_x=pymunk_obj.body.position.x, center_y=pymunk_obj.body.position.y)
|
super().__init__(filename, center_x=pymunk_obj.body.position.x, center_y=pymunk_obj.body.position.y)
|
||||||
self.pymunk_obj = pymunk_obj
|
self.pymunk_obj = pymunk_obj
|
||||||
self.origin_x = 0
|
|
||||||
self.origin_y = 0
|
|
||||||
|
|
||||||
class PhysicsCoin(SpritePhysics):
|
class PhysicsCoin(SpritePhysics):
|
||||||
def __init__(self, pymunk_obj, filename):
|
def __init__(self, pymunk_obj, filename):
|
||||||
super().__init__(pymunk_obj, filename)
|
super().__init__(pymunk_obj, filename)
|
||||||
@@ -38,10 +47,36 @@ class Game(arcade.gui.UIView):
|
|||||||
|
|
||||||
arcade.set_background_color(arcade.color.WHITE)
|
arcade.set_background_color(arcade.color.WHITE)
|
||||||
|
|
||||||
|
if os.path.exists("data.json"):
|
||||||
|
with open("data.json", "r") as file:
|
||||||
|
self.settings = json.load(file)
|
||||||
|
else:
|
||||||
|
self.settings = {}
|
||||||
|
|
||||||
|
if not "physics_playground" in self.settings:
|
||||||
|
self.settings["physics_playground"] = {
|
||||||
|
"iterations": 50,
|
||||||
|
"gravity_x": 0,
|
||||||
|
"gravity_y": -930,
|
||||||
|
|
||||||
|
"crate_elasticity": 0.5,
|
||||||
|
"crate_friction": 0.9,
|
||||||
|
"crate_mass": 1,
|
||||||
|
|
||||||
|
"coin_elasticity": 0.5,
|
||||||
|
"coin_friction": 0.9,
|
||||||
|
"coin_mass": 1,
|
||||||
|
|
||||||
|
"custom_elasticity": 0.5,
|
||||||
|
"custom_friction": 0.9,
|
||||||
|
"custom_mass": 1
|
||||||
|
}
|
||||||
|
|
||||||
self.space = pymunk.Space()
|
self.space = pymunk.Space()
|
||||||
|
|
||||||
self.spritelist: arcade.SpriteList[SpritePhysics] = arcade.SpriteList()
|
self.spritelist: arcade.SpriteList[SpritePhysics] = arcade.SpriteList()
|
||||||
self.walls = []
|
self.walls = []
|
||||||
|
self.custom_bodies = []
|
||||||
|
|
||||||
self.custom_pymunk_objs = {}
|
self.custom_pymunk_objs = {}
|
||||||
|
|
||||||
@@ -49,20 +84,24 @@ class Game(arcade.gui.UIView):
|
|||||||
self.last_mouse_position = 0, 0
|
self.last_mouse_position = 0, 0
|
||||||
self.last_processing_time_update = time.perf_counter()
|
self.last_processing_time_update = time.perf_counter()
|
||||||
|
|
||||||
self.iterations = 35
|
self.iterations = self.settings["physics_playground"].get("iterations", 35)
|
||||||
self.space.iterations = self.iterations
|
self.space.iterations = self.iterations
|
||||||
|
|
||||||
self.gravity_x = 0
|
self.gravity_x = self.settings["physics_playground"].get("gravity_x", 0)
|
||||||
self.gravity_y = -900
|
self.gravity_y = self.settings["physics_playground"].get("gravity_y", -930)
|
||||||
self.space.gravity = (self.gravity_x, self.gravity_y)
|
self.space.gravity = (self.gravity_x, self.gravity_y)
|
||||||
|
|
||||||
self.crate_elasticity = 0.5
|
self.crate_elasticity = self.settings["physics_playground"].get("crate_elasticity", 0.5)
|
||||||
self.crate_friction = 0.9
|
self.crate_friction = self.settings["physics_playground"].get("crate_friction", 0.9)
|
||||||
self.crate_mass = 1
|
self.crate_mass = self.settings["physics_playground"].get("crate_mass", 1)
|
||||||
|
|
||||||
self.coin_elasticity = 0.5
|
self.coin_elasticity = self.settings["physics_playground"].get("coin_elasticity", 0.5)
|
||||||
self.coin_friction = 0.9
|
self.coin_friction = self.settings["physics_playground"].get("coin_friction", 0.9)
|
||||||
self.coin_mass = 1
|
self.coin_mass = self.settings["physics_playground"].get("coin_mass", 1)
|
||||||
|
|
||||||
|
self.custom_elasticity = self.settings["physics_playground"].get("custom_elasticity", 0.5)
|
||||||
|
self.custom_friction = self.settings["physics_playground"].get("custom_friction", 0.9)
|
||||||
|
self.custom_mass = self.settings["physics_playground"].get("custom_mass", 1)
|
||||||
|
|
||||||
self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1)))
|
self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1)))
|
||||||
|
|
||||||
@@ -71,26 +110,43 @@ class Game(arcade.gui.UIView):
|
|||||||
self.object_count_label = self.info_box.add(arcade.gui.UILabel(text="Object count: 0", text_color=arcade.color.BLACK))
|
self.object_count_label = self.info_box.add(arcade.gui.UILabel(text="Object count: 0", text_color=arcade.color.BLACK))
|
||||||
self.processing_time_label = self.info_box.add(arcade.gui.UILabel(text="Processing time: 0 ms", text_color=arcade.color.BLACK))
|
self.processing_time_label = self.info_box.add(arcade.gui.UILabel(text="Processing time: 0 ms", text_color=arcade.color.BLACK))
|
||||||
|
|
||||||
self.settings_box = self.anchor.add(arcade.gui.UIBoxLayout(space_between=5, align="center", size_hint=(0.2, 1)).with_background(color=arcade.color.GRAY), anchor_x="right", anchor_y="bottom")
|
self.settings_box = self.anchor.add(arcade.gui.UIBoxLayout(align="center", size_hint=(0.2, 1)).with_background(color=arcade.color.GRAY), anchor_x="right", anchor_y="bottom")
|
||||||
self.settings_title_label = self.settings_box.add(arcade.gui.UILabel(text="Settings", font_size=24))
|
self.settings_title_label = self.settings_box.add(arcade.gui.UILabel(text="Settings", font_size=24))
|
||||||
|
|
||||||
self.settings_box.add(arcade.gui.UISpace(size_hint=(0, 0.025)))
|
self.settings_box.add(arcade.gui.UISpace(size_hint=(0, 0.025)))
|
||||||
|
|
||||||
self.add_setting("Crate Elasticity: {value}", 0, 3, 0.1, "crate_elasticity", "elasticity", PhysicsCrate)
|
self.add_setting("Crate Elasticity: {value}", 0, 3, 0.1, "crate_elasticity", "elasticity", PhysicsCrate)
|
||||||
self.add_setting("Coin Elasticity: {value}", 0, 3, 0.1, "coin_elasticity", "elasticity", PhysicsCoin)
|
self.add_setting("Coin Elasticity: {value}", 0, 3, 0.1, "coin_elasticity", "elasticity", PhysicsCoin)
|
||||||
|
self.add_setting("Custom Elasticity: {value}", 0, 3, 0.1, "custom_elasticity", "elasticity", CustomPhysics)
|
||||||
|
|
||||||
self.add_setting("Crate Friction: {value}", 0, 10, 0.1, "crate_friction", "friction", PhysicsCrate)
|
self.add_setting("Crate Friction: {value}", 0, 10, 0.1, "crate_friction", "friction", PhysicsCrate)
|
||||||
self.add_setting("Coin Friction: {value}", 0, 10, 0.1, "coin_friction", "friction", PhysicsCoin)
|
self.add_setting("Coin Friction: {value}", 0, 10, 0.1, "coin_friction", "friction", PhysicsCoin)
|
||||||
|
self.add_setting("Custom Friction: {value}", 0, 10, 0.1, "custom_friction", "friction", CustomPhysics)
|
||||||
|
|
||||||
self.add_setting("Crate Mass: {value}kg", 1, 100, 1, "crate_mass", "mass", PhysicsCrate)
|
self.add_setting("Crate Mass: {value}kg", 1, 100, 1, "crate_mass", "mass", PhysicsCrate)
|
||||||
self.add_setting("Coin Mass: {value}kg", 1, 100, 1, "coin_mass", "mass", PhysicsCoin)
|
self.add_setting("Coin Mass: {value}kg", 1, 100, 1, "coin_mass", "mass", PhysicsCoin)
|
||||||
|
self.add_setting("Custom Mass: {value}kg", 1, 100, 1, "custom_mass", "mass", CustomPhysics)
|
||||||
|
|
||||||
self.add_setting("Gravity X: {value}", -900, 900, 100, "gravity_x", on_change=lambda label, value: self.change_gravity(label, value, "x"))
|
self.add_setting("Gravity X: {value}", -900, 900, 100, "gravity_x", on_change=lambda label, value: self.change_gravity(label, value, "x"))
|
||||||
self.add_setting("Gravity Y: {value}", -1800, 1800, 100, "gravity_y", on_change=lambda label, value: self.change_gravity(label, value, "y"))
|
self.add_setting("Gravity Y: {value}", -1800, 1800, 100, "gravity_y", on_change=lambda label, value: self.change_gravity(label, value, "y"))
|
||||||
|
self.add_setting("Pymunk Iterations: {value}", 1, 200, 1, "iterations", on_change=lambda label, value: self.change_iterations(label, value))
|
||||||
|
|
||||||
|
self.settings_box.add(arcade.gui.UILabel("Inventory", font_size=18))
|
||||||
|
|
||||||
self.inventory_grid = self.settings_box.add(BodyInventory(self.window.width, self.window.height, "crate", {"crate": ":resources:images/tiles/boxCrate_double.png", "coin": ":resources:images/items/coinGold.png"}))
|
self.inventory_grid = self.settings_box.add(BodyInventory(self.window.width, self.window.height, "crate", {"crate": ":resources:images/tiles/boxCrate_double.png", "coin": ":resources:images/items/coinGold.png"}))
|
||||||
|
|
||||||
self.add_custom_body_button = self.settings_box.add(arcade.gui.UITextureButton(text="Add custom body from SVG", size_hint=(1, 0.1), width=self.window.width * 0.2, height=self.window.height * 0.1))
|
self.add_custom_body_button = self.settings_box.add(arcade.gui.UITextureButton(text="Add custom body from SVG", size_hint=(1, 0.1), width=self.window.width * 0.2, height=self.window.height * 0.1))
|
||||||
self.add_custom_body_button.on_click = lambda event: self.custom_body_ui()
|
self.add_custom_body_button.on_click = lambda event: self.custom_body_ui()
|
||||||
|
|
||||||
|
def save_data(self):
|
||||||
|
with open("data.json", "w") as file:
|
||||||
|
file.write(json.dumps(self.settings, indent=4))
|
||||||
|
|
||||||
|
def change_iterations(self, label, value):
|
||||||
|
self.iterations = int(value)
|
||||||
|
self.space.iterations = self.iterations
|
||||||
|
label.text = f"Pymunk Iterations: {self.iterations}"
|
||||||
|
|
||||||
def change_gravity(self, label, value, gravity_type):
|
def change_gravity(self, label, value, gravity_type):
|
||||||
if gravity_type == "x":
|
if gravity_type == "x":
|
||||||
self.gravity_x = value
|
self.gravity_x = value
|
||||||
@@ -117,6 +173,8 @@ class Game(arcade.gui.UIView):
|
|||||||
|
|
||||||
setattr(self, local_variable, value)
|
setattr(self, local_variable, value)
|
||||||
|
|
||||||
|
self.settings["physics_playground"][local_variable] = value
|
||||||
|
|
||||||
if pymunk_variable:
|
if pymunk_variable:
|
||||||
for sprite in self.spritelist:
|
for sprite in self.spritelist:
|
||||||
if isinstance(sprite, instance):
|
if isinstance(sprite, instance):
|
||||||
@@ -131,7 +189,7 @@ class Game(arcade.gui.UIView):
|
|||||||
self.walls.append(pymunk_obj)
|
self.walls.append(pymunk_obj)
|
||||||
|
|
||||||
def create_crate(self, x, y, size, mass):
|
def create_crate(self, x, y, size, mass):
|
||||||
pymunk_moment = pymunk.moment_for_box(mass, (size, size))
|
pymunk_moment = pymunk.moment_for_box(1.0, (size, size))
|
||||||
|
|
||||||
pymunk_body = pymunk.Body(mass, pymunk_moment)
|
pymunk_body = pymunk.Body(mass, pymunk_moment)
|
||||||
pymunk_body.position = pymunk.Vec2d(x, y)
|
pymunk_body.position = pymunk.Vec2d(x, y)
|
||||||
@@ -146,7 +204,7 @@ class Game(arcade.gui.UIView):
|
|||||||
self.spritelist.append(sprite)
|
self.spritelist.append(sprite)
|
||||||
|
|
||||||
def create_coin(self, x, y, radius, mass):
|
def create_coin(self, x, y, radius, mass):
|
||||||
inertia = pymunk.moment_for_circle(mass, 0, radius, (0, 0))
|
inertia = pymunk.moment_for_circle(1.0, 0, radius, (0, 0))
|
||||||
|
|
||||||
body = pymunk.Body(mass, inertia)
|
body = pymunk.Body(mass, inertia)
|
||||||
body.position = x, y
|
body.position = x, y
|
||||||
@@ -173,6 +231,12 @@ class Game(arcade.gui.UIView):
|
|||||||
|
|
||||||
arcade.draw_line(pv1.x, pv1.y, pv2.x, pv2.y, arcade.color.BLACK, 2)
|
arcade.draw_line(pv1.x, pv1.y, pv2.x, pv2.y, arcade.color.BLACK, 2)
|
||||||
|
|
||||||
|
for body in self.custom_bodies:
|
||||||
|
for shape in body.shapes:
|
||||||
|
if isinstance(shape, pymunk.Poly):
|
||||||
|
verts = [v.rotated(body.angle) + body.position for v in shape.get_vertices()]
|
||||||
|
arcade.draw_polygon_filled(verts, arcade.color.BLACK)
|
||||||
|
|
||||||
def on_mouse_press(self, x, y, button, modifiers):
|
def on_mouse_press(self, x, y, button, modifiers):
|
||||||
if button == arcade.MOUSE_BUTTON_LEFT:
|
if button == arcade.MOUSE_BUTTON_LEFT:
|
||||||
self.last_mouse_position = x, y
|
self.last_mouse_position = x, y
|
||||||
@@ -219,7 +283,7 @@ class Game(arcade.gui.UIView):
|
|||||||
def add_custom_body(self, file_path):
|
def add_custom_body(self, file_path):
|
||||||
paths, _ = svg2paths(file_path)
|
paths, _ = svg2paths(file_path)
|
||||||
|
|
||||||
pts = self.sample_path(paths[0], 15)
|
pts = self.sample_path(paths[0], 64)
|
||||||
|
|
||||||
png_bytes = cairosvg.svg2png(url=file_path, scale=1.0)
|
png_bytes = cairosvg.svg2png(url=file_path, scale=1.0)
|
||||||
original_image = Image.open(io.BytesIO(png_bytes)).convert("RGBA")
|
original_image = Image.open(io.BytesIO(png_bytes)).convert("RGBA")
|
||||||
@@ -229,32 +293,36 @@ class Game(arcade.gui.UIView):
|
|||||||
scale_factor = desired_width / original_width
|
scale_factor = desired_width / original_width
|
||||||
|
|
||||||
pts = [(x * scale_factor, y * scale_factor) for x, y in pts]
|
pts = [(x * scale_factor, y * scale_factor) for x, y in pts]
|
||||||
|
|
||||||
|
try:
|
||||||
|
convex_parts = convex_decomposition(pts, 0.1)
|
||||||
|
except AssertionError:
|
||||||
|
convex_parts = [pymunk.util.convex_hull(pts)]
|
||||||
|
|
||||||
hull = pymunk.util.convex_hull(pts)
|
total_moment = sum(pymunk.moment_for_poly(1.0, part) for part in convex_parts)
|
||||||
moment = pymunk.moment_for_poly(1.0, hull)
|
|
||||||
|
|
||||||
png_bytes = cairosvg.svg2png(url=file_path, scale=scale_factor)
|
png_bytes = cairosvg.svg2png(url=file_path, scale=scale_factor)
|
||||||
image = Image.open(io.BytesIO(png_bytes)).convert("RGBA")
|
image = Image.open(io.BytesIO(png_bytes)).convert("RGBA")
|
||||||
texture = arcade.Texture(image)
|
texture = arcade.Texture(image)
|
||||||
|
|
||||||
self.custom_pymunk_objs[file_path] = (hull, moment, texture)
|
self.custom_pymunk_objs[file_path] = (convex_parts, total_moment, texture)
|
||||||
self.inventory_grid.add_item(file_path, texture)
|
self.inventory_grid.add_item(file_path, texture)
|
||||||
|
|
||||||
self.clear_custom_body_ui()
|
self.clear_custom_body_ui()
|
||||||
|
|
||||||
def create_custom_body(self, file_path, x, y, mass):
|
def create_custom_body(self, file_path, x, y, mass):
|
||||||
hull, moment, image = self.custom_pymunk_objs[file_path]
|
convex_parts, moment, image = self.custom_pymunk_objs[file_path]
|
||||||
|
|
||||||
body = pymunk.Body(mass, moment)
|
body = pymunk.Body(mass, moment)
|
||||||
body.position = pymunk.Vec2d(x, y)
|
body.position = pymunk.Vec2d(x, y)
|
||||||
|
|
||||||
shape = pymunk.Poly(body, hull)
|
self.space.add(body)
|
||||||
|
|
||||||
self.space.add(body, shape)
|
|
||||||
|
|
||||||
sprite = SpritePhysics(shape, image)
|
for part in convex_parts:
|
||||||
sprite.origin_x = image.width / 2
|
shape = pymunk.Poly(body, part)
|
||||||
sprite.origin_y = image.height / 2
|
self.space.add(shape)
|
||||||
|
|
||||||
|
sprite = CustomPhysics(FakeShape(body), image)
|
||||||
|
|
||||||
self.spritelist.append(sprite)
|
self.spritelist.append(sprite)
|
||||||
|
|
||||||
@@ -326,13 +394,15 @@ class Game(arcade.gui.UIView):
|
|||||||
elif self.inventory_grid.selected_item == "coin":
|
elif self.inventory_grid.selected_item == "coin":
|
||||||
self.create_coin(self.window.mouse.data['x'], self.window.mouse.data['y'], 10, self.coin_mass)
|
self.create_coin(self.window.mouse.data['x'], self.window.mouse.data['y'], 10, self.coin_mass)
|
||||||
else:
|
else:
|
||||||
self.create_custom_body(self.inventory_grid.selected_item, self.window.mouse.data['x'], self.window.mouse.data['y'], 1.0)
|
self.create_custom_body(self.inventory_grid.selected_item, self.window.mouse.data['x'], self.window.mouse.data['y'], self.custom_mass)
|
||||||
|
|
||||||
for sprite in self.spritelist:
|
for sprite in self.spritelist:
|
||||||
if sprite.pymunk_obj.body.position.x < 0 or sprite.pymunk_obj.body.position.x > self.window.width * 0.8 or sprite.pymunk_obj.body.position.y < 0:
|
body = sprite.pymunk_obj.body
|
||||||
self.space.remove(sprite.pymunk_obj, sprite.pymunk_obj.body)
|
x, y = body.position
|
||||||
|
|
||||||
sprite.remove_from_sprite_lists()
|
if x < 0 or x > self.window.width * 0.775 or y < 0:
|
||||||
|
body.position = (random.uniform(self.window.width * 0.1, self.window.width * 0.9), self.window.height * 0.9)
|
||||||
|
body.velocity = (0, 0)
|
||||||
|
|
||||||
start = time.perf_counter()
|
start = time.perf_counter()
|
||||||
self.space.step(self.window._draw_rate)
|
self.space.step(self.window._draw_rate)
|
||||||
@@ -342,8 +412,7 @@ class Game(arcade.gui.UIView):
|
|||||||
self.dragged_shape.shape.body.velocity = 0, 0
|
self.dragged_shape.shape.body.velocity = 0, 0
|
||||||
|
|
||||||
for sprite in self.spritelist:
|
for sprite in self.spritelist:
|
||||||
sprite.center_x = sprite.pymunk_obj.body.position.x + sprite.origin_x
|
sprite.position = sprite.pymunk_obj.body.position
|
||||||
sprite.center_y = sprite.pymunk_obj.body.position.y + sprite.origin_y
|
|
||||||
sprite.angle = -math.degrees(sprite.pymunk_obj.body.angle)
|
sprite.angle = -math.degrees(sprite.pymunk_obj.body.angle)
|
||||||
|
|
||||||
self.object_count_label.text = f"Object count: {len(self.spritelist)}"
|
self.object_count_label.text = f"Object count: {len(self.spritelist)}"
|
||||||
@@ -356,13 +425,21 @@ 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:
|
||||||
arcade.set_background_color(menu_background_color)
|
arcade.set_background_color(menu_background_color)
|
||||||
|
|
||||||
|
self.save_data()
|
||||||
|
|
||||||
from menus.main import Main
|
from menus.main import Main
|
||||||
self.window.show_view(Main(self.pypresence_client))
|
self.window.show_view(Main(self.pypresence_client))
|
||||||
elif symbol == arcade.key.D:
|
elif symbol == arcade.key.D:
|
||||||
self.create_wall((self.window.width * 0.8) / 10, 80, self.window.mouse.data["x"] - (self.window.width * 0.8) / 20, self.window.mouse.data["y"] - 80)
|
self.create_wall((self.window.width * 0.8) / 10, 80, self.window.mouse.data["x"] - (self.window.width * 0.8) / 20, self.window.mouse.data["y"] - 80)
|
||||||
elif symbol == arcade.key.C:
|
elif symbol == arcade.key.C:
|
||||||
for sprite in self.spritelist:
|
for sprite in self.spritelist:
|
||||||
self.space.remove(sprite.pymunk_obj, sprite.pymunk_obj.body)
|
if not isinstance(sprite.pymunk_obj, FakeShape):
|
||||||
|
self.space.remove(sprite.pymunk_obj, sprite.pymunk_obj.body)
|
||||||
|
else:
|
||||||
|
for shape in sprite.pymunk_obj.body.shapes:
|
||||||
|
self.space.remove(shape)
|
||||||
|
self.space.remove(sprite.pymunk_obj.body)
|
||||||
|
|
||||||
self.spritelist.clear()
|
self.spritelist.clear()
|
||||||
|
|
||||||
146
game/water_simulator/game.py
Normal file
146
game/water_simulator/game.py
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
import arcade, arcade.gui, pyglet.gl, array, random, os, json
|
||||||
|
|
||||||
|
from utils.constants import WATER_ROWS, WATER_COLS
|
||||||
|
from game.water_simulator.shader import create_shader
|
||||||
|
|
||||||
|
class Game(arcade.gui.UIView):
|
||||||
|
def __init__(self, pypresence_client):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.pypresence_client = pypresence_client
|
||||||
|
self.pypresence_client.update(state="Playing a simulator", details="Water Simulator")
|
||||||
|
|
||||||
|
self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1)))
|
||||||
|
|
||||||
|
self.settings_box = self.anchor.add(arcade.gui.UIBoxLayout(align="center", size_hint=(0.2, 1)).with_background(color=arcade.color.GRAY), anchor_x="right", anchor_y="bottom")
|
||||||
|
self.settings_label = self.settings_box.add(arcade.gui.UILabel(text="Settings", font_size=24))
|
||||||
|
|
||||||
|
if os.path.exists("data.json"):
|
||||||
|
with open("data.json", "r") as file:
|
||||||
|
self.settings = json.load(file)
|
||||||
|
else:
|
||||||
|
self.settings = {}
|
||||||
|
|
||||||
|
if not "water_simulator" in self.settings:
|
||||||
|
self.settings["water_simulator"] = {
|
||||||
|
"splash_strength": 0.1,
|
||||||
|
"splash_radius": 3,
|
||||||
|
"wave_speed": 1,
|
||||||
|
"damping": 0.02
|
||||||
|
}
|
||||||
|
|
||||||
|
self.splash_row = 0
|
||||||
|
self.splash_col = 0
|
||||||
|
self.current_splash_strength = 0
|
||||||
|
|
||||||
|
self.splash_strength = self.settings["water_simulator"].get("splash_strength", 0.1)
|
||||||
|
self.splash_radius = self.settings["water_simulator"].get("splash_radius", 3)
|
||||||
|
|
||||||
|
self.wave_speed = self.settings["water_simulator"].get("wave_speed", 1)
|
||||||
|
self.damping = self.settings["water_simulator"].get("damping", 0.02)
|
||||||
|
|
||||||
|
def on_show_view(self):
|
||||||
|
super().on_show_view()
|
||||||
|
|
||||||
|
self.settings_box.add(arcade.gui.UISpace(height=self.window.height / 75))
|
||||||
|
|
||||||
|
self.add_setting("Splash Strength: {value}", 0.1, 2.0, 0.1, "splash_strength")
|
||||||
|
self.add_setting("Splash Radius: {value}", 0.5, 10, 0.5, "splash_radius")
|
||||||
|
|
||||||
|
self.settings_box.add(arcade.gui.UISpace(height=self.window.height / 50))
|
||||||
|
|
||||||
|
self.advanced_label = self.settings_box.add(arcade.gui.UILabel("Advanced Settings", font_size=18, multiline=True))
|
||||||
|
|
||||||
|
self.settings_box.add(arcade.gui.UISpace(height=self.window.height / 75))
|
||||||
|
|
||||||
|
self.add_setting("Wave Speed: {value}", 0.1, 1.25, 0.05, "wave_speed")
|
||||||
|
self.add_setting("Damping: {value}", 0.005, 0.05, 0.001, "damping")
|
||||||
|
self.setup_game()
|
||||||
|
|
||||||
|
def on_update(self, delta_time):
|
||||||
|
with self.shader_program:
|
||||||
|
self.shader_program["rows"] = WATER_ROWS
|
||||||
|
self.shader_program["cols"] = WATER_COLS
|
||||||
|
|
||||||
|
self.shader_program["splash_row"] = self.splash_row
|
||||||
|
self.shader_program["splash_col"] = self.splash_col
|
||||||
|
self.shader_program["splash_strength"] = self.current_splash_strength
|
||||||
|
self.shader_program["splash_radius"] = self.splash_radius
|
||||||
|
|
||||||
|
self.shader_program["wave_speed"] = self.wave_speed
|
||||||
|
self.shader_program["damping"] = self.damping
|
||||||
|
|
||||||
|
self.shader_program.dispatch(self.water_image.width, self.water_image.height, 1, barrier=pyglet.gl.GL_ALL_BARRIER_BITS)
|
||||||
|
|
||||||
|
self.current_splash_strength = 0
|
||||||
|
|
||||||
|
def save_data(self):
|
||||||
|
self.settings.update({
|
||||||
|
"water_simulator": {
|
||||||
|
"splash_strength": self.splash_strength,
|
||||||
|
"splash_radius": self.splash_radius,
|
||||||
|
"wave_speed": self.wave_speed,
|
||||||
|
"damping": self.damping
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
with open("data.json", "w") as file:
|
||||||
|
file.write(json.dumps(self.settings, indent=4))
|
||||||
|
|
||||||
|
def setup_game(self):
|
||||||
|
self.shader_program, self.water_image, self.previous_heights_ssbo, self.current_heights_ssbo = create_shader()
|
||||||
|
|
||||||
|
self.image_sprite = pyglet.sprite.Sprite(img=self.water_image)
|
||||||
|
|
||||||
|
scale_x = (self.window.width * 0.8) / self.image_sprite.width
|
||||||
|
scale_y = self.window.height / self.image_sprite.height
|
||||||
|
|
||||||
|
self.image_sprite.scale_x = scale_x
|
||||||
|
self.image_sprite.scale_y = scale_y
|
||||||
|
|
||||||
|
grid = array.array('f', [random.uniform(-0.01, 0.01) for _ in range(WATER_ROWS * WATER_COLS)])
|
||||||
|
|
||||||
|
self.previous_heights_ssbo.set_data(grid.tobytes())
|
||||||
|
self.current_heights_ssbo.set_data(grid.tobytes())
|
||||||
|
|
||||||
|
def add_setting(self, text, min_value, max_value, step, local_variable, on_change=None):
|
||||||
|
label = self.settings_box.add(arcade.gui.UILabel(text.format(value=getattr(self, local_variable))))
|
||||||
|
slider = self.settings_box.add(arcade.gui.UISlider(value=getattr(self, local_variable), min_value=min_value, max_value=max_value, step=step))
|
||||||
|
slider._render_steps = lambda surface: None
|
||||||
|
|
||||||
|
if on_change:
|
||||||
|
slider.on_change = lambda event, label=label: on_change(label, event.new_value)
|
||||||
|
else:
|
||||||
|
slider.on_change = lambda event, label=label: self.change_value(label, text, local_variable, event.new_value)
|
||||||
|
|
||||||
|
def change_value(self, label, text, local_variable, value):
|
||||||
|
label.text = text.format(value=value)
|
||||||
|
|
||||||
|
self.settings["water_simulator"][local_variable] = value
|
||||||
|
|
||||||
|
setattr(self, local_variable, value)
|
||||||
|
|
||||||
|
def main_exit(self):
|
||||||
|
self.shader_program.delete()
|
||||||
|
self.previous_heights_ssbo.delete()
|
||||||
|
self.current_heights_ssbo.delete()
|
||||||
|
|
||||||
|
def on_key_press(self, symbol, modifiers):
|
||||||
|
if symbol == arcade.key.ESCAPE:
|
||||||
|
self.save_data()
|
||||||
|
|
||||||
|
from menus.main import Main
|
||||||
|
self.window.show_view(Main(self.pypresence_client))
|
||||||
|
|
||||||
|
def on_mouse_press(self, x, y, button, modifiers):
|
||||||
|
col = int(x / (self.window.width * 0.8) * WATER_COLS)
|
||||||
|
row = int(y / self.window.height * WATER_ROWS)
|
||||||
|
|
||||||
|
self.splash_row = row
|
||||||
|
self.splash_col = col
|
||||||
|
self.current_splash_strength = self.splash_strength
|
||||||
|
|
||||||
|
def on_draw(self):
|
||||||
|
super().on_draw()
|
||||||
|
|
||||||
|
self.image_sprite.draw()
|
||||||
80
game/water_simulator/shader.py
Normal file
80
game/water_simulator/shader.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import pyglet, pyglet.graphics
|
||||||
|
|
||||||
|
from pyglet.gl import glBindBufferBase, GL_SHADER_STORAGE_BUFFER, GL_NEAREST
|
||||||
|
|
||||||
|
from utils.constants import WATER_ROWS, WATER_COLS
|
||||||
|
|
||||||
|
shader_source = f"""#version 430 core
|
||||||
|
|
||||||
|
layout(std430, binding = 3) buffer PreviousHeights {{
|
||||||
|
float previous_heights[{WATER_ROWS * WATER_COLS}];
|
||||||
|
}};
|
||||||
|
|
||||||
|
layout(std430, binding = 4) buffer CurrentHeights {{
|
||||||
|
float current_heights[{WATER_ROWS * WATER_COLS}];
|
||||||
|
}};
|
||||||
|
|
||||||
|
uniform int rows;
|
||||||
|
uniform int cols;
|
||||||
|
uniform int splash_row;
|
||||||
|
uniform int splash_col;
|
||||||
|
uniform float damping;
|
||||||
|
uniform float wave_speed;
|
||||||
|
uniform float splash_strength;
|
||||||
|
uniform float splash_radius;
|
||||||
|
|
||||||
|
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||||
|
layout (location = 0, rgba32f) uniform image2D img_output;
|
||||||
|
|
||||||
|
void main() {{
|
||||||
|
ivec2 texel_coord = ivec2(gl_GlobalInvocationID.xy);
|
||||||
|
|
||||||
|
int row = texel_coord.y * rows / imageSize(img_output).y;
|
||||||
|
int col = texel_coord.x * cols / imageSize(img_output).x;
|
||||||
|
int current_index = (row * cols) + col;
|
||||||
|
|
||||||
|
if(row == 0 || col == 0 || row == rows-1 || col == cols-1) return;
|
||||||
|
|
||||||
|
float dist = distance(vec2(row, col), vec2(splash_row, splash_col));
|
||||||
|
if(dist <= splash_radius) current_heights[current_index] += splash_strength * (1.0 - dist / splash_radius);
|
||||||
|
|
||||||
|
float laplacian = current_heights[(row - 1) * cols + col] +
|
||||||
|
current_heights[(row + 1) * cols + col] +
|
||||||
|
current_heights[row * cols + (col - 1)] +
|
||||||
|
current_heights[row * cols + (col + 1)] -
|
||||||
|
4.0 * current_heights[current_index];
|
||||||
|
|
||||||
|
float dt = 0.1;
|
||||||
|
|
||||||
|
float h_new = 2.0 * current_heights[current_index]
|
||||||
|
- previous_heights[current_index] +
|
||||||
|
(wave_speed * wave_speed)*(dt*dt) * laplacian -
|
||||||
|
damping * (current_heights[current_index] - previous_heights[current_index]);
|
||||||
|
|
||||||
|
previous_heights[current_index] = current_heights[current_index];
|
||||||
|
current_heights[current_index] = h_new;
|
||||||
|
|
||||||
|
float minH = -0.5;
|
||||||
|
float maxH = 0.5;
|
||||||
|
float normH = clamp((h_new - minH) / (maxH - minH), 0.0, 1.0);
|
||||||
|
|
||||||
|
imageStore(img_output, texel_coord, vec4(0.0, 0.0, normH, 1.0));
|
||||||
|
}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def create_shader():
|
||||||
|
shader_program = pyglet.graphics.shader.ComputeShaderProgram(shader_source)
|
||||||
|
|
||||||
|
water_image = pyglet.image.Texture.create(WATER_COLS, WATER_ROWS, internalformat=pyglet.gl.GL_RGBA32F, min_filter=GL_NEAREST, mag_filter=GL_NEAREST)
|
||||||
|
|
||||||
|
uniform_location = shader_program['img_output']
|
||||||
|
water_image.bind_image_texture(unit=uniform_location)
|
||||||
|
|
||||||
|
previous_heights_ssbo = pyglet.graphics.BufferObject(WATER_COLS * WATER_ROWS * 4, usage=pyglet.gl.GL_DYNAMIC_COPY)
|
||||||
|
current_heights_ssbo = pyglet.graphics.BufferObject(WATER_COLS * WATER_ROWS * 4, usage=pyglet.gl.GL_DYNAMIC_COPY)
|
||||||
|
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, previous_heights_ssbo.id)
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, current_heights_ssbo.id)
|
||||||
|
|
||||||
|
return shader_program, water_image, previous_heights_ssbo, current_heights_ssbo
|
||||||
@@ -52,21 +52,28 @@ class Main(arcade.gui.UIView):
|
|||||||
|
|
||||||
self.title_label = self.box.add(arcade.gui.UILabel(text="Simulator Games", font_name="Roboto", font_size=48))
|
self.title_label = self.box.add(arcade.gui.UILabel(text="Simulator Games", font_name="Roboto", font_size=48))
|
||||||
|
|
||||||
self.boid_simulator_button = self.box.add(arcade.gui.UITextureButton(text="Boid Simulator", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=150, style=big_button_style))
|
self.boid_simulator_button = self.box.add(arcade.gui.UITextureButton(text="Boid Simulator", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=self.window.height / 8, style=big_button_style))
|
||||||
self.boid_simulator_button.on_click = lambda event: self.boid_simulator()
|
self.boid_simulator_button.on_click = lambda event: self.boid_simulator()
|
||||||
|
|
||||||
self.physics_playground_button = self.box.add(arcade.gui.UITextureButton(text="Physics Playground", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=150, style=big_button_style))
|
self.water_simulator_button = self.box.add(arcade.gui.UITextureButton(text="Water Simulator", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=self.window.height / 8, style=big_button_style))
|
||||||
|
self.water_simulator_button.on_click = lambda event: self.water_simulator()
|
||||||
|
|
||||||
|
self.physics_playground_button = self.box.add(arcade.gui.UITextureButton(text="Physics Playground", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=self.window.height / 8, style=big_button_style))
|
||||||
self.physics_playground_button.on_click = lambda event: self.physics_playground()
|
self.physics_playground_button.on_click = lambda event: self.physics_playground()
|
||||||
|
|
||||||
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 / 8, style=big_button_style))
|
||||||
self.settings_button.on_click = lambda event: self.settings()
|
self.settings_button.on_click = lambda event: self.settings()
|
||||||
|
|
||||||
def physics_playground(self):
|
def physics_playground(self):
|
||||||
from game.physics_playground import Game
|
from game.physics_playground.game import Game
|
||||||
self.window.show_view(Game(self.pypresence_client))
|
self.window.show_view(Game(self.pypresence_client))
|
||||||
|
|
||||||
def boid_simulator(self):
|
def boid_simulator(self):
|
||||||
from game.boid_simulator import Game
|
from game.boid_simulator.game import Game
|
||||||
|
self.window.show_view(Game(self.pypresence_client))
|
||||||
|
|
||||||
|
def water_simulator(self):
|
||||||
|
from game.water_simulator.game import Game
|
||||||
self.window.show_view(Game(self.pypresence_client))
|
self.window.show_view(Game(self.pypresence_client))
|
||||||
|
|
||||||
def settings(self):
|
def settings(self):
|
||||||
|
|||||||
2
run.py
2
run.py
@@ -25,7 +25,7 @@ timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
|||||||
log_filename = f"debug_{timestamp}.log"
|
log_filename = f"debug_{timestamp}.log"
|
||||||
logging.basicConfig(filename=f'{os.path.join(log_dir, log_filename)}', format='%(asctime)s %(name)s %(levelname)s: %(message)s', level=logging.DEBUG)
|
logging.basicConfig(filename=f'{os.path.join(log_dir, log_filename)}', format='%(asctime)s %(name)s %(levelname)s: %(message)s', level=logging.DEBUG)
|
||||||
|
|
||||||
for logger_name_to_disable in ['arcade', "numba"]:
|
for logger_name_to_disable in ['arcade', "pymunk.shapes", "PIL", "Pillow"]:
|
||||||
logging.getLogger(logger_name_to_disable).propagate = False
|
logging.getLogger(logger_name_to_disable).propagate = False
|
||||||
logging.getLogger(logger_name_to_disable).disabled = True
|
logging.getLogger(logger_name_to_disable).disabled = True
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ from arcade.gui.widgets.slider import UISliderStyle
|
|||||||
SMALL_RADIUS = 75
|
SMALL_RADIUS = 75
|
||||||
LARGE_RADIUS = 150
|
LARGE_RADIUS = 150
|
||||||
|
|
||||||
|
WATER_ROWS = 128
|
||||||
|
WATER_COLS = 128
|
||||||
|
|
||||||
menu_background_color = (30, 30, 47)
|
menu_background_color = (30, 30, 47)
|
||||||
log_dir = 'logs'
|
log_dir = 'logs'
|
||||||
discord_presence_id = 1414634708414758972
|
discord_presence_id = 1414634708414758972
|
||||||
|
|||||||
Reference in New Issue
Block a user