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:
77
game/boid_simulator/boid.py
Normal file
77
game/boid_simulator/boid.py
Normal file
@@ -0,0 +1,77 @@
|
||||
import arcade, arcade.math, random, math
|
||||
|
||||
class Boid(arcade.Sprite):
|
||||
def __init__(self, boid_num, x, y):
|
||||
super().__init__(arcade.load_texture("assets/graphics/boid.png"), center_x=x, center_y=y)
|
||||
|
||||
random_angle = random.randint(0, 361)
|
||||
|
||||
self.boid_num = boid_num
|
||||
self.direction = arcade.math.Vec2(math.cos(random_angle), math.sin(random_angle))
|
||||
|
||||
self.velocity = 5
|
||||
self.radius = 10
|
||||
|
||||
self.w_separation = 1.0
|
||||
self.w_cohesion = 1.0
|
||||
self.w_alignment = 1.0
|
||||
self.small_radius = 100
|
||||
self.large_radius = 250
|
||||
|
||||
def calculate_separation(self, neighbours: list[int, arcade.math.Vec2, arcade.math.Vec2]):
|
||||
steeraway_vectors = [arcade.math.Vec2(*self.position) - neighbour[2] for neighbour in neighbours]
|
||||
|
||||
if not steeraway_vectors:
|
||||
return self.direction
|
||||
|
||||
return (sum(steeraway_vectors) / len(steeraway_vectors)).normalize()
|
||||
|
||||
def calculate_alignment(self, neighbours: list[int, arcade.math.Vec2, arcade.math.Vec2]):
|
||||
directions = [neighbour[1] for neighbour in neighbours]
|
||||
|
||||
if not directions:
|
||||
return self.direction
|
||||
|
||||
return (sum(directions) / len(directions)).normalize()
|
||||
|
||||
def calculate_cohesion(self, neighbours: list[int, arcade.math.Vec2, arcade.math.Vec2]):
|
||||
positions = [neighbour[2] for neighbour in neighbours]
|
||||
|
||||
if not positions:
|
||||
return self.direction
|
||||
|
||||
return ((sum(positions) / len(positions)) - self.position).normalize()
|
||||
|
||||
def update(self, window_width, window_height, boids):
|
||||
small_radius_neighbours, large_radius_neighbours = [], []
|
||||
for boid_data in boids:
|
||||
distance = boid_data[2].distance(arcade.math.Vec2(*self.position))
|
||||
if boid_data[0] == self.boid_num or distance > self.large_radius:
|
||||
continue
|
||||
|
||||
if distance <= self.small_radius:
|
||||
small_radius_neighbours.append(boid_data)
|
||||
|
||||
large_radius_neighbours.append(boid_data)
|
||||
|
||||
self.direction = self.w_separation * self.calculate_separation(small_radius_neighbours) + self.w_alignment * self.calculate_alignment(large_radius_neighbours) + self.w_cohesion * self.calculate_cohesion(large_radius_neighbours)
|
||||
|
||||
if self.direction.length() > 1:
|
||||
self.direction = self.direction.normalize()
|
||||
|
||||
self.position += self.direction * self.velocity
|
||||
self.angle = 90 - math.degrees(self.direction.heading())
|
||||
|
||||
if self.center_x <= self.radius:
|
||||
self.center_x = self.radius
|
||||
self.direction = self.direction.reflect(arcade.math.Vec2(1, 0))
|
||||
elif self.center_x >= (window_width * 0.8) - self.radius:
|
||||
self.center_x = (window_width * 0.8) - self.radius
|
||||
self.direction = self.direction.reflect(arcade.math.Vec2(-1, 0))
|
||||
|
||||
if self.center_y <= self.radius:
|
||||
self.center_y = self.radius
|
||||
self.direction = self.direction.reflect(arcade.math.Vec2(0, 1))
|
||||
elif self.center_y >= window_height - self.radius:
|
||||
self.center_y = window_height - self.radius
|
||||
self.direction = self.direction.reflect(arcade.math.Vec2(0, -1))
|
||||
88
game/boid_simulator/game.py
Normal file
88
game/boid_simulator/game.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import arcade, arcade.gui, random, os, json
|
||||
|
||||
from game.boid_simulator.boid import Boid
|
||||
|
||||
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='Boids simulator', start=self.pypresence_client.start_time)
|
||||
self.boid_sprites = arcade.SpriteList()
|
||||
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.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_label = self.settings_box.add(arcade.gui.UILabel(text="Settings", font_size=24))
|
||||
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("Cohesion Weight: {value}", 0.1, 5, 0.1, "w_cohesion")
|
||||
self.add_setting("Small Radius: {value}", 25, 250, 25, "small_radius")
|
||||
self.add_setting("Large Radius: {value}", 50, 500, 50, "large_radius")
|
||||
|
||||
def save_data(self):
|
||||
with open("data.json", "w") as file:
|
||||
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.on_change = lambda event, label=label: self.change_value(label, text, boid_variable, event.new_value)
|
||||
|
||||
def change_value(self, label, text, boid_variable, value):
|
||||
label.text = text.format(value=value)
|
||||
|
||||
self.settings["boid_simulator"][boid_variable] = value
|
||||
|
||||
for boid in self.boid_sprites:
|
||||
setattr(boid, boid_variable, value)
|
||||
|
||||
def create_boid(self, x, y):
|
||||
boid = Boid(self.current_boid_num, x, y)
|
||||
self.boid_sprites.append(boid)
|
||||
self.current_boid_num += 1
|
||||
|
||||
def setup_boids(self):
|
||||
for i in range(25):
|
||||
self.create_boid(random.randint(self.window.width / 2 - 150, self.window.width / 2), random.randint(self.window.height / 2 - 150, self.window.height / 2))
|
||||
|
||||
def on_show_view(self):
|
||||
super().on_show_view()
|
||||
self.setup_boids()
|
||||
|
||||
def on_update(self, delta_time):
|
||||
boid_directions = [(boid.boid_num, boid.direction, arcade.math.Vec2(*boid.position)) for boid in self.boid_sprites]
|
||||
for boid in self.boid_sprites:
|
||||
boid.update(self.window.width, self.window.height, boid_directions)
|
||||
|
||||
if self.window.mouse[arcade.MOUSE_BUTTON_LEFT]:
|
||||
self.create_boid(self.window.mouse.data["x"], self.window.mouse.data["y"])
|
||||
|
||||
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_draw(self):
|
||||
super().on_draw()
|
||||
self.boid_sprites.draw()
|
||||
Reference in New Issue
Block a user