From b9a280208b13a6348da7ddeadbeb41d61786043d Mon Sep 17 00:00:00 2001 From: Stan44 Date: Thu, 26 Dec 2024 19:16:46 -0600 Subject: [PATCH] made several changes working on zoom added proper particle count there is a settings menu some keybindings have been added ESC to exit Glowing particles are now a thing Gas effects can be toggled on and off for performance --- .gitignore | 3 + __pycache__/rendering.cpython-312.pyc | Bin 11840 -> 15970 bytes __pycache__/sim.cpython-312.pyc | Bin 30584 -> 31611 bytes rendering.py | 111 +++++++++++++++++++++----- sandpypi.py | 62 +++++++++++++- settings.py | 8 ++ sim.py | 27 ++++++- template_particles.json | 80 +++++++++++++++++++ 8 files changed, 261 insertions(+), 30 deletions(-) create mode 100644 template_particles.json diff --git a/.gitignore b/.gitignore index 4effda0..d6bab80 100644 --- a/.gitignore +++ b/.gitignore @@ -163,3 +163,6 @@ cython_debug/ current_stations.html forecast_data.json openapi.json +__pycache__/sim.cpython-312.pyc +__pycache__/sim.cpython-312.pyc +__pycache__/rendering.cpython-312.pyc diff --git a/__pycache__/rendering.cpython-312.pyc b/__pycache__/rendering.cpython-312.pyc index fc4b5ac7f50f3bb46ec82b2e0590bef6101d4939..e2d25c4ba4047fa20b3c8c6d2316d6603cb2766f 100644 GIT binary patch delta 6003 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 delta 2737 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 delta 1651 zcmZ{kYfM~K5P$9=Z5=|SoMw%FjXATj5sOQI*IdkUB z%$+lH|NMj8y+xuvjf@Nz*eblx=34A{C(0k8A7k4W1c%T_>_VexPl4MJLz?bnB~?AG ziw-3UjK|D@ry@*zO@LcqjFGTqJ80r?4!qnT1Glj&YW6@wyCBg$ona)wUy z0*3gChpL&-FZ`g@&1;kV+N61Hx?h|Ar8eVQY~p;Z;*V8=0tqW8M|TXA5BRR>^z*uG zzb<>Ee!S`Brpa=Dj(O7O&)GV?ak}{{UDl(<14I4Tfa$mTEN&5^@{@x!L3dT(6B0sRLs3GRc%$oHr&CH+*Ak(NhfGiKswq zhiY#;*z-4&S#>ynzqn>4A&X7XQZJ;L($=0tO9KNdIu5AU5A-l%n8Bt*u#d4|X%Dk-ef}A)8>Pz$ zy@8SVi+00e={QMOUn=v-WC)@yNro5kkbglGN|>z@Nxdjr5!lGA0yUOI_ULX)y2*!% zG6c3XZA1(r{=2?Y78fZ|*Hv~)xmdJ?a0d5HRsow5_OCGLW)v=3OUWoKSrbB<2pgIS zc+M237Cta2$pOjZXot(TGS*sh^>)&#?y7!R)C1mo5K)Pkfp=@!v!U3@I?zV?)xx?l z+1Q4fc7~tN4C7iTU2PX7iVrevMjJ0I?XeIa>}**7kDIOr4>_vdXjs%m&M^}WzK7@_Nsy(ty&#^-TyiSetA$-27Cg^KOd!r6&Vt@mPd-!~u9Kkz;BNc+{KuG{&5jX|KR{eW z@G7l3d>?fe*!0y9vpV8U)({KKbpE8i(p5%v#IFAh116!F diff --git a/rendering.py b/rendering.py index 1b89da8..1d9c9aa 100644 --- a/rendering.py +++ b/rendering.py @@ -1,6 +1,7 @@ #File Name: rendering.py -from settings import pygame, random, particle_properties +from settings import pygame, random, particle_properties, engine_settings + class Rendering: @@ -69,31 +70,68 @@ class Rendering: base_color = particle_colors.get(particle.particle_type, (255, 255, 255)) color = list(base_color) - - if particle.is_gas: - # Enhanced gas visibility - alpha = random.randint(128, 200) - color = list(color) - if len(color) < 4: - color.append(alpha) - else: - color[3] = alpha - - # Add subtle movement effect - offset_x = random.randint(-1, 1) - offset_y = random.randint(-1, 1) - rect = (x * particle_size + offset_x, y * particle_size + offset_y, - particle_size, particle_size) - else: - rect = (x * particle_size, y * particle_size, - particle_size, particle_size) + if engine_settings['enable_glow']: + glow_color = (255, 255, 255) + glow_radius = 0.5 * particle_size + glow_surface = pygame.Surface((glow_radius * 2, glow_radius * 2), pygame.SRCALPHA) + pygame.draw.circle(glow_surface, glow_color, (glow_radius, glow_radius), glow_radius) + glow_surface.set_alpha(100) + self.particle_surface.blit(glow_surface, (x * particle_size - glow_radius, y * particle_size - glow_radius)) + + if engine_settings['enable_gas_effect']: + if particle.is_gas: + # Enhanced gas visibility + alpha = random.randint(128, 200) + color = list(color) + if len(color) < 4: + color.append(alpha) + else: + color[3] = alpha + + # Add subtle movement effect + offset_x = random.randint(-1, 1) + offset_y = random.randint(-1, 1) + rect = (x * particle_size + offset_x, y * particle_size + offset_y, + particle_size, particle_size) + + rect = (x * particle_size, y * particle_size, + particle_size, particle_size) + pygame.draw.rect(self.particle_surface, color, rect) self.screen.blit(self.background, (0, 0)) self.screen.blit(self.particle_surface, (0, 0)) + def draw_zoom_window(self, particles, particle_size, particle_colors, mouse_pos, zoom_factor=4): + print(f"Drawing zoom window.") + zoom_size = 100 # Size of zoom window + zoom_surface = pygame.Surface((zoom_size, zoom_size)) + zoom_surface.fill((0, 0, 0)) + + # Get area around mouse to zoom + mouse_x, mouse_y = mouse_pos + view_x = mouse_x - zoom_size/(2*zoom_factor) + view_y = mouse_y - zoom_size/(2*zoom_factor) + print(f"Viewing area: {view_x}, {view_y}") + + # Draw zoomed particles + for x in range(int(view_x), int(view_x + zoom_size/zoom_factor)): + for y in range(int(view_y), int(view_y + zoom_size/zoom_factor)): + if 0 <= x < len(particles) and 0 <= y < len(particles[0]): + particle = particles[x][y] + if particle: + color = particle_colors.get(particle.particle_type, (255, 255, 255)) + rect = ((x - view_x) * zoom_factor, + (y - view_y) * zoom_factor, + particle_size * zoom_factor, + particle_size * zoom_factor) + pygame.draw.rect(zoom_surface, color, rect) + print(f"Drawing zoom window at {mouse_pos}{zoom_surface}") + return zoom_surface + + def draw_debug_overlay(self, fps, particles): # this is the function that draws the debug overlay # Get mouse position and convert to grid coordinates mouse_x, mouse_y = pygame.mouse.get_pos() @@ -124,13 +162,16 @@ class Rendering: # Draw debug information font = pygame.font.SysFont(None, 24) + particle_count = sum(1 for row in particles for cell in row if cell is not None) + debug_info = [ f"FPS: {int(fps)}", f"Mouse: ({mouse_x}, {mouse_y})", f"Grid: ({grid_x}, {grid_y})", - f"Particle: {particle_info}" + f"Particle: {particle_info}", + #f"Active Particle Count: {sim.Simulation.get_active_particle_count(sim.Simulation)}", + f"Particle Count: {particle_count}" ] - y_offset = 10 for info in debug_info: debug_text = font.render(info, True, (255, 255, 255)) @@ -175,6 +216,13 @@ class Rendering: label = font.render("Clear", True, (255, 255, 255)) self.screen.blit(label, (self.clear_screen_button.x + 5, self.clear_screen_button.y + 5)) + # Draw Settings menu directly below the buttons + self.settings_button = pygame.Rect(x_offset, y_offset + 50, 80, 25) + pygame.draw.rect(self.screen, (255, 255, 255), self.settings_button) + font = pygame.font.SysFont(None, 24) + label = font.render("Settings", True, (0, 0, 0)) + self.screen.blit(label, (self.settings_button.x + 5, self.settings_button.y + 5)) + def render_brush_curser(self, x, y, radius): # this is the function that draws the brush curser but isn't used yet so unkown if works # Draw a circle cursor for brushsize @@ -189,8 +237,27 @@ class Rendering: label = pygame.font.SysFont(None, 24).render(f"Brush Size: {brush_size}", True, (255, 255, 255)) self.screen.blit(label, (500, 10)) + def draw_settings_menu(self): + settings_surface = pygame.Surface((300, 400)) + settings_surface.fill((50, 50, 50)) + + y_offset = 10 + font = pygame.font.SysFont(None, 24) + + for setting, value in engine_settings.items(): + # Create toggle button + button_rect = pygame.Rect(10, y_offset, 20, 20) + pygame.draw.rect(settings_surface, (0, 255, 0) if value else (255, 0, 0), button_rect) + + # Draw setting name + label = font.render(setting.replace('_', ' ').title(), True, (255, 255, 255)) + settings_surface.blit(label, (40, y_offset)) + + y_offset += 30 + + return settings_surface - def clear_screen(self, sim): ## this is the function that clears the screen + def clear_screen(self, sim): # this is the function that clears the screen # Store current particle type current_type = sim.current_particle_type diff --git a/sandpypi.py b/sandpypi.py index ae689bc..435e07d 100644 --- a/sandpypi.py +++ b/sandpypi.py @@ -5,27 +5,36 @@ # This is my most functional system for falling sand in python yet i took some things i learned in JS. # This needs further optimizations to core performance sections. -from settings import pygame +from settings import pygame, engine_settings from rendering import Rendering from sim import Simulation def main(): # Main function to run the program pygame.init() clock = pygame.time.Clock() - pygame.display.set_mode((1024, 768), pygame.HWSURFACE | pygame.DOUBLEBUF) - sim = Simulation(1024, 768) - rendering = Rendering(1024, 768) + width = 1024 + height = 768 + screen = pygame.display.set_mode((width, height), pygame.HWSURFACE | pygame.DOUBLEBUF) + sim = Simulation(width, height) + rendering = Rendering(width, height) mouse_down_left = False mouse_down_right = False mouse_down_middle = False mouse_down_wheel_up = False mouse_down_wheel_down = False over_button = False + zoom_active = False + zoom_locked = False + zoom_pos = None + settings_visible = False + settings_menu_y = 100 running = True while running: fps = clock.get_fps() dt = clock.tick(60) / 1000 + keys = pygame.key.get_pressed() + zoom_active = keys[pygame.K_z] # Handle events @@ -38,6 +47,11 @@ def main(): # Main function to run the program sim.brush_size = max(sim.brush_size - 1, 1) elif event.button == 1: # Left click over_button = False + + if zoom_active: + zoom_locked = not zoom_locked + if zoom_locked: + zoom_pos = mouse_pos # Check category buttons for category, button in rendering.category_buttons.items(): @@ -59,6 +73,18 @@ def main(): # Main function to run the program rendering.clear_screen(sim) over_button = True + if rendering.settings_button.collidepoint(event.pos): + settings_visible = not settings_visible + elif settings_visible: + # Handle settings toggles + mouse_pos = pygame.mouse.get_pos() + relative_y = mouse_pos[1] - settings_menu_y + setting_index = relative_y // 30 + if 0 <= setting_index < len(engine_settings): + setting_name = list(engine_settings.keys())[setting_index] + engine_settings[setting_name] = not engine_settings[setting_name] + + if not over_button: mouse_down_left = True @@ -74,6 +100,23 @@ def main(): # Main function to run the program mouse_down_right = False elif event.type == pygame.MOUSEBUTTONUP and event.button == 2: mouse_down_middle = False + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + print("Escape button pressed") + print(f"Exiting Program {__file__}") + running = False + elif event.key == pygame.K_SPACE: + print(f"Pause button pressed but not functional 'Space'") + pass + elif event.key == pygame.K_c: + rendering.clear_screen(sim) + elif event.key == pygame.K_z: + zoom_active = not zoom_active + if zoom_active: + zoom_locked = False + zoom_pos = pygame.mouse.get_pos() + + elif event.type == pygame.QUIT: running = False @@ -94,6 +137,17 @@ def main(): # Main function to run the program rendering.draw_particles(sim.particles, sim.active_particles, sim.particle_size, rendering.particle_colors) rendering.draw_buttons() rendering.draw_brush_size_slider(sim.brush_size) + if zoom_active or zoom_locked: + mouse_pos = zoom_pos if zoom_locked else pygame.mouse.get_pos() + zoom_surface = rendering.draw_zoom_window(sim.particles, sim.particle_size, rendering.particle_colors, mouse_pos) + # Position zoom window + zoom_x = 10 if mouse_pos[0] > width/2 else width - 110 + zoom_y = 10 if mouse_pos[1] > height/2 else height - 110 + screen.blit(zoom_surface, (zoom_x, zoom_y)) + + if settings_visible: + settings_menu = rendering.draw_settings_menu() + rendering.screen.blit(settings_menu, (rendering.width - 320, 100)) rendering.draw_debug_overlay(fps, sim.particles) pygame.display.flip() diff --git a/settings.py b/settings.py index e3bdf50..d2d62ef 100644 --- a/settings.py +++ b/settings.py @@ -6,6 +6,13 @@ import json import random import time +engine_settings = { + 'enable_glow': True, + 'enable_gas_effect': True + # 'settings': True/False +} + +# Load particle properties from JSON file def load_particle_properties(): try: with open('particles.json') as f: @@ -16,3 +23,4 @@ def load_particle_properties(): # Load particle properties once when module is imported particle_properties = load_particle_properties() + diff --git a/sim.py b/sim.py index e9e529c..9a393d8 100644 --- a/sim.py +++ b/sim.py @@ -100,10 +100,14 @@ class Simulation: def update_spatial_grid(self): # this is where we update the spatial grid. """Update spatial grid for optimized collision detection""" - self.spatial_grid.clear() - for x, y in self.active_particles: - self.add_to_spatial_grid(self.particles[x][y], x, y) - + if len(self.active_particles) > 100: # Threshold for rebuild + self.spatial_grid.clear() + for x, y in self.active_particles: + cell_key = self.get_cell_key(x, y) + if cell_key not in self.spatial_grid: + self.spatial_grid[cell_key] = set() + self.spatial_grid[cell_key].add((x, y)) + def handle_phase_transitions(self, particle, x, y): # this is where we handle all the phase transitions. @@ -593,6 +597,21 @@ class Simulation: liquid2.color = self.calculate_color(liquid2.temperature) + def get_particle_count(self): + """Returns the number of particles in the simulation for the Debug display and for performance analysis.""" + count = 0 + for x in range(self.width): + for y in range(self.height): + if self.particles[x][y] is not None: + count += 1 + return count + + def get_active_particle_count(self): + """Returns the number of active particles in the simulation for the Debug display and for performance analysis.""" + pass + + + def simulate_step(self, dt): """Run a single step of the simulation""" # Update particle positions and physics diff --git a/template_particles.json b/template_particles.json new file mode 100644 index 0000000..1e48019 --- /dev/null +++ b/template_particles.json @@ -0,0 +1,80 @@ +{ + "Template": { + "description": "This is a template for particles.", + "description2": "Remove this for your own particle mods to work" + }, + "sand": { + "name": "Sand", + "size": 1, + "hardness": 0.5, + "color": [255, 255, 0, 255], + "velocity": 0.5, + "mass": 0.5, + "conductivity": 0, + "heat_capacity": 1, + "flamability": 0.8, + "temperature": 0, + "explosive": false, + "explosion_radius": 0, + "explosion_color": [0, 0, 0], + "friction": 0.5, + "viscosity": 0, + "pressure": 0, + "melt": "molten-Glass", + "melt_temperature": 1000, + "conductive": false, + "liquid": false, + "solid": true, + "is_gas": false + }, + "water": { + "name": "Water", + "size": 1, + "hardness": 0.2, + "velocity": 0.3, + "conductivity": 1, + "heat_capacity": 1, + "color": [0, 0, 255, 255], + "mass": 1, + "flamability": 0, + "temperature": 22, + "explosive": false, + "explosion_radius": 0, + "explosion_color": [0, 0, 0], + "friction": 1, + "viscosity": 1, + "pressure": 0.5, + "evaporate": "steam", + "evaporate_temperature": 145, + "freeze": "ice", + "freeze_temperature": 0, + "melt": "water", + "melt_temperature": 20, + "liquid": true, + "solid": false, + "is_gas": false + }, + "steam": { + "name": "Steam", + "size": 1, + "hardness": 0.0, + "velocity": 0.2, + "conductivity": 1, + "heat_capacity": 1, + "color": [255, 255, 255, 255], + "mass": 0.01, + "flamability": 0, + "temperature": 100, + "solidify_temperature": 98, + "solidify": "water", + "explosive": false, + "explosion_radius": 0, + "explosion_color": [0, 0, 0], + "friction": 0.5, + "viscosity": 0.5, + "liquid": false, + "solid": false, + "is_gas": true, + "conductive": false + } +} \ No newline at end of file