sandpypi/sandpypi.py
Stan44 986750c722 Massive changes to the repository have been made.
feat: Performance optimizations and UI improvements

- Added dormant state tracking for static particles
- Fixed settings menu particle spawn overlap
- Optimized particle batch processing
- Added brush cursor visualization
- Improved UI interaction zones
- Enhanced gas particle effects
- Added glow toggle functionality disabled by default due to performance impact
- Fixed particle rendering issues
- Debug Overlay Disabled by default
- FPS counter added semi seperate from Debug Overlay, Turn this one off when using Debug Overlay
- Improved particle rendering performance

Performance improvements focus on reducing unnecessary calculations for static particles while maintaining core simulation mechanics. UI changes prevent unwanted particle spawning during menu interactions.
2024-12-27 07:39:31 -06:00

190 lines
7.8 KiB
Python

"""
#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.
The main function to run the Sandpypi program.
This function initializes the Pygame environment, creates the simulation and rendering objects, and enters the main event loop.
It handles user input events such as mouse clicks, mouse wheel scrolling, and keyboard presses.
It also updates the simulation, draws the particles, buttons, and other UI elements, and manages the settings menu.
The main loop runs at a target frame rate of 60 FPS, with the actual frame rate displayed in the debug overlay.
"""
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() # Get the current frame rate
dt = clock.tick(300) / 1000 # sets the target frame rate to 60 FPS
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()
# Check if clicking in settings area when menu is visible
in_settings_area = False
if settings_visible:
settings_rect = pygame.Rect(rendering.width - 320, 100, 300, 400)
in_settings_area = settings_rect.collidepoint(mouse_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
# Check settings button first
if rendering.settings_button.collidepoint(mouse_pos):
settings_visible = not settings_visible
over_button = True
if zoom_active:
zoom_locked = not zoom_locked
if zoom_locked:
zoom_pos = mouse_pos
# Handle settings menu interactions
elif settings_visible and in_settings_area:
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]
over_button = True
elif not in_settings_area:
# 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 not over_button and not in_settings_area:
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)
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))
# Draw Settings
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()
# Update and draw particles
sim.simulate_step(dt=0.016)
# Draw particles
rendering.draw_particles(sim.particles, sim.active_particles, sim.particle_size, rendering.particle_colors)
# Draw buttons
rendering.draw_buttons()
# Draw brush size slider
rendering.draw_brush_size_slider(sim.brush_size)
# Get current mouse position
mouse_x, mouse_y = pygame.mouse.get_pos()
# Draw brush cursor at mouse position
rendering.render_brush_cursor(mouse_x, mouse_y, sim.brush_size * sim.particle_size)
pygame.quit()
if __name__ == "__main__":
main()