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
272 lines
12 KiB
Python
272 lines
12 KiB
Python
#File Name: rendering.py
|
|
|
|
from settings import pygame, random, particle_properties, engine_settings
|
|
|
|
|
|
class Rendering:
|
|
|
|
def __init__(self, width, height):
|
|
self.screen = pygame.display.set_mode((width, height))
|
|
self.background = pygame.Surface((width, height))
|
|
self.background.fill((0, 0, 0))
|
|
self.width = width
|
|
self.height = height
|
|
self.particle_surface = pygame.Surface((width, height), pygame.SRCALPHA)
|
|
self.particle_colors = {}
|
|
self.button_width, self.button_height = 30, 30
|
|
self.particle_properties = particle_properties
|
|
self.buttons = {}
|
|
self.clear_screen_button = pygame.Rect(915, 10, 50, 30)
|
|
self.load_buttons() # Load buttons dynamically
|
|
self.particle_colors = {}
|
|
for name, properties in particle_properties.items():
|
|
if 'color' in properties:
|
|
self.particle_colors[name.lower()] = properties['color']
|
|
self.categories = {'Solids': [], 'Liquids': [], 'Gases': [], 'Special': []}
|
|
for particle_name, properties in self.particle_properties.items():
|
|
if properties.get('is_gas'):
|
|
self.categories['Gases'].append(particle_name)
|
|
elif properties.get('liquid'):
|
|
self.categories['Liquids'].append(particle_name)
|
|
elif properties.get('solid'):
|
|
self.categories['Solids'].append(particle_name)
|
|
else:
|
|
self.categories['Special'].append(particle_name)
|
|
|
|
self.current_category = 'Solids'
|
|
self.category_buttons = {}
|
|
self.setup_category_menu()
|
|
|
|
|
|
def setup_category_menu(self):
|
|
# Category buttons at the top
|
|
x_offset = self.width - 350
|
|
y_offset = 10
|
|
for category in self.categories:
|
|
button_rect = pygame.Rect(x_offset, y_offset, 80, 25)
|
|
self.category_buttons[category] = button_rect
|
|
x_offset += 90
|
|
|
|
|
|
def load_buttons(self):
|
|
x_offset = 10
|
|
y_offset = 10
|
|
|
|
for particle_type, properties in self.particle_properties.items():
|
|
if 'color' in properties:
|
|
button_rect = pygame.Rect(x_offset, y_offset, self.button_width, self.button_height)
|
|
self.buttons[particle_type.lower()] = button_rect
|
|
x_offset += self.button_width + 10 # Add spacing between buttons
|
|
|
|
|
|
def draw_particles(self, particles, active_particles, particle_size, particle_colors): # this is the function that draws the particles
|
|
self.particle_surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
|
|
self.particle_surface.fill((0, 0, 0, 0))
|
|
|
|
for x, y in active_particles:
|
|
particle = particles[x][y]
|
|
if not particle:
|
|
continue
|
|
|
|
base_color = particle_colors.get(particle.particle_type, (255, 255, 255))
|
|
color = list(base_color)
|
|
|
|
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()
|
|
grid_x = mouse_x // 3
|
|
grid_y = mouse_y // 3
|
|
|
|
# Get particle info under cursor
|
|
particle_info = "None"
|
|
if 0 <= grid_x < len(particles) and 0 <= grid_y < len(particles[0]):
|
|
particle = particles[grid_x][grid_y]
|
|
if particle:
|
|
# Include more detailed particle information
|
|
particle_info = f"Type: {particle.particle_type}"
|
|
if hasattr(particle, 'temperature'):
|
|
particle_info += f" | Temp: {particle.temperature}°C"
|
|
if hasattr(particle, 'liquid'):
|
|
particle_info += f" | Liquid: {particle.liquid}"
|
|
if hasattr(particle, 'is_gas'):
|
|
particle_info += f" | Gas: {particle.is_gas}"
|
|
if hasattr(particle, 'solid'):
|
|
particle_info += f" | Solid: {particle.solid}"
|
|
if hasattr(particle, 'mass'):
|
|
particle_info += f" | Mass: {particle.mass}"
|
|
if hasattr(particle, 'velocity'):
|
|
particle_info += f" | Velocity: {particle.velocity}"
|
|
if hasattr(particle, 'friction'):
|
|
particle_info += f" | Friction: {particle.friction}"
|
|
|
|
# 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"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))
|
|
self.screen.blit(debug_text, (10, y_offset))
|
|
y_offset += 25
|
|
|
|
|
|
def draw_buttons(self): # this is the function that draws the buttons
|
|
self.buttons = {}
|
|
|
|
# Draw category buttons vertically on right
|
|
x_offset = self.width - 100
|
|
y_offset = 10
|
|
for category, button in self.category_buttons.items():
|
|
color = (200, 200, 200) if category == self.current_category else (150, 150, 150)
|
|
pygame.draw.rect(self.screen, color, button)
|
|
font = pygame.font.SysFont(None, 20)
|
|
label = font.render(category, True, (0, 0, 0))
|
|
self.screen.blit(label, (button.x + 5, button.y + 5))
|
|
|
|
# Draw particle buttons for current category
|
|
y_offset = 150 # Start particle buttons below categories
|
|
for particle_type in self.categories[self.current_category]:
|
|
if particle_type in self.particle_properties:
|
|
color = self.particle_properties[particle_type].get('color', (255, 255, 255))
|
|
button_rect = pygame.Rect(x_offset, y_offset, 80, 25)
|
|
self.buttons[particle_type] = button_rect
|
|
|
|
pygame.draw.rect(self.screen, color, button_rect)
|
|
pygame.draw.rect(self.screen, (0, 0, 0), button_rect, 2)
|
|
|
|
font = pygame.font.SysFont(None, 20)
|
|
label = font.render(particle_type, True, (0, 0, 0))
|
|
self.screen.blit(label, (x_offset + 5, y_offset + 5))
|
|
|
|
y_offset += 30 # Stack buttons vertically
|
|
|
|
# Draw clear screen button
|
|
self.clear_screen_button = pygame.Rect(x_offset, y_offset + 10, 80, 25)
|
|
pygame.draw.rect(self.screen, (255, 0, 0), self.clear_screen_button)
|
|
font = pygame.font.SysFont(None, 24)
|
|
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
|
|
pygame.draw.circle(self.screen, (255, 255, 255), (x, y), radius)
|
|
|
|
|
|
def draw_brush_size_slider(self, brush_size): # this is the function that draws the brush size slider
|
|
# Draw the slider for brush size
|
|
pygame.draw.rect(self.screen, (255, 255, 255), (500, 10, 100, 20))
|
|
pygame.draw.rect(self.screen, (0, 0, 0), (500, 10, 100, 20), 2)
|
|
pygame.draw.rect(self.screen, (255, 0, 0), (500 + brush_size, 10, 100 - brush_size * 2, 20))
|
|
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
|
|
# Store current particle type
|
|
current_type = sim.current_particle_type
|
|
|
|
# Reset simulation grid while preserving particle type
|
|
sim.particles = [[None for _ in range(sim.height)] for _ in range(sim.width)]
|
|
sim.active_particles.clear()
|
|
sim.current_particle_type = current_type
|
|
|
|
# Clear display surfaces
|
|
self.background.fill((0, 0, 0))
|
|
self.particle_surface.fill((0, 0, 0, 0))
|