#File Name: sandpypi.py # Sandpypi by Stanton. # Project name is a placeholder. # This has been a multimonth or year project i have time blindness sorta. # 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, engine_settings from rendering import Rendering from sim import Simulation def main(): # Main function to run the program pygame.init() clock = pygame.time.Clock() 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 for event in pygame.event.get(): if event.type == pygame.MOUSEBUTTONDOWN: mouse_pos = pygame.mouse.get_pos() if event.button == 4: # Mouse wheel up sim.brush_size = min(sim.brush_size + 1, sim.max_brush_size) elif event.button == 5: # Mouse wheel down 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(): if button.collidepoint(mouse_pos): rendering.current_category = category over_button = True break # Check particle buttons if not over_button: for particle_type, button in rendering.buttons.items(): if button.collidepoint(mouse_pos): sim.current_particle_type = particle_type over_button = True break # Check clear screen button if rendering.clear_screen_button.collidepoint(mouse_pos): 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 elif event.button == 3: # Right click mouse_down_right = True elif event.button == 2: # Middle click mouse_down_middle = True elif event.type == pygame.MOUSEBUTTONUP and event.button == 1: mouse_down_left = False elif event.type == pygame.MOUSEBUTTONUP and event.button == 3: 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 if mouse_down_left and not over_button: x, y = pygame.mouse.get_pos() sim.create_particle_circle(x, y) if mouse_down_right: x, y = pygame.mouse.get_pos() sim.clear_particles_circle(x, y) if mouse_down_middle: x, y = pygame.mouse.get_pos() sim.create_particle(x, y) sim.simulate_step(dt) 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() pygame.quit() if __name__ == "__main__": main()