195 lines
8.0 KiB
Python
195 lines
8.0 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()
|
|
# Check if current particle type is wind or air
|
|
if sim.current_particle_type not in ['wind', 'air']:
|
|
sim.create_particle_circle(x, y)
|
|
else:
|
|
# Handle wind/air differently
|
|
sim.add_wind_zone(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()
|