Refactor HUD to support dynamic panel resizing and improve layout management
This commit is contained in:
parent
d5d44c5d14
commit
6f9e1e84f0
@ -13,11 +13,8 @@ class Renderer:
|
||||
self.render_height = render_area.get_height()
|
||||
self.render_width = render_area.get_width()
|
||||
|
||||
def clear_screen(self, main_screen=None):
|
||||
def clear_screen(self):
|
||||
"""Clear the screen with a black background."""
|
||||
if main_screen:
|
||||
main_screen.fill(BLACK)
|
||||
|
||||
self.render_area.fill(BLACK)
|
||||
|
||||
def draw_grid(self, camera, showing_grid=True):
|
||||
|
||||
@ -18,21 +18,29 @@ from ui.hud import HUD
|
||||
class SimulationEngine:
|
||||
def __init__(self):
|
||||
pygame.init()
|
||||
self._init_window()
|
||||
self._init_ui()
|
||||
self._init_simulation()
|
||||
self.running = True
|
||||
|
||||
def _init_window(self):
|
||||
info = pygame.display.Info()
|
||||
self.window_width, self.window_height = info.current_w // 2, info.current_h // 2
|
||||
self.screen = pygame.display.set_mode((self.window_width, self.window_height),
|
||||
pygame.RESIZABLE, vsync=1)
|
||||
|
||||
self.ui_manager = UIManager((self.window_width, self.window_height))
|
||||
|
||||
self.camera = Camera(SCREEN_WIDTH, SCREEN_HEIGHT, RENDER_BUFFER)
|
||||
self._update_simulation_view()
|
||||
|
||||
# self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), vsync=1)
|
||||
self.window_width = int(info.current_w // 1.5)
|
||||
self.window_height = int(info.current_h // 1.5)
|
||||
self.screen = pygame.display.set_mode(
|
||||
(self.window_width, self.window_height),
|
||||
pygame.RESIZABLE, vsync=1
|
||||
)
|
||||
pygame.display.set_caption("Dynamic Abstraction System Testing")
|
||||
self.clock = pygame.time.Clock()
|
||||
|
||||
def _init_ui(self):
|
||||
self.ui_manager = UIManager((self.window_width, self.window_height))
|
||||
self.hud = HUD(self.ui_manager, self.window_width, self.window_height)
|
||||
self.hud.update_layout(self.window_width, self.window_height)
|
||||
self._update_simulation_view()
|
||||
|
||||
def _init_simulation(self):
|
||||
self.last_tick_time = time.perf_counter()
|
||||
self.last_tps_time = time.perf_counter()
|
||||
self.tick_counter = 0
|
||||
@ -42,21 +50,17 @@ class SimulationEngine:
|
||||
self.world = self._setup_world()
|
||||
self.input_handler = InputHandler(self.camera, self.world, self.sim_view_rect)
|
||||
self.renderer = Renderer(self.sim_view)
|
||||
self.hud = HUD(self.ui_manager, self.window_width, self.window_height)
|
||||
self.hud.update_layout(self.window_width, self.window_height)
|
||||
|
||||
self.running = True
|
||||
|
||||
def _update_simulation_view(self):
|
||||
self.sim_view_width = int(self.window_width * 0.75)
|
||||
self.sim_view_height = int(self.window_height * 0.75)
|
||||
viewport_rect = self.hud.get_viewport_rect()
|
||||
self.sim_view_width = viewport_rect.width
|
||||
self.sim_view_height = viewport_rect.height
|
||||
self.sim_view = pygame.Surface((self.sim_view_width, self.sim_view_height))
|
||||
self.sim_view_rect = self.sim_view.get_rect(center=(self.window_width // 2, self.window_height // 2))
|
||||
self.sim_view_rect = self.sim_view.get_rect(topleft=(viewport_rect.left, viewport_rect.top))
|
||||
|
||||
self.ui_manager.set_window_resolution((self.window_width, self.window_height))
|
||||
self.renderer = Renderer(self.sim_view)
|
||||
|
||||
# Update camera to match new sim_view size
|
||||
if hasattr(self, 'camera'):
|
||||
self.camera.screen_width = self.sim_view_width
|
||||
self.camera.screen_height = self.sim_view_height
|
||||
@ -64,6 +68,8 @@ class SimulationEngine:
|
||||
if hasattr(self, 'input_handler'):
|
||||
self.input_handler.update_sim_view_rect(self.sim_view_rect)
|
||||
|
||||
if not hasattr(self, 'camera'):
|
||||
self.camera = Camera(self.sim_view_width, self.sim_view_height, RENDER_BUFFER)
|
||||
|
||||
@staticmethod
|
||||
def _setup_world():
|
||||
@ -80,10 +86,11 @@ class SimulationEngine:
|
||||
world.add_object(FoodObject(Position(x=x, y=y)))
|
||||
|
||||
for _ in range(300):
|
||||
new_cell = DefaultCell(Position(x=random.randint(-half_width, half_width), y=random.randint(-half_height, half_height)), Rotation(angle=0))
|
||||
|
||||
new_cell = DefaultCell(
|
||||
Position(x=random.randint(-half_width, half_width), y=random.randint(-half_height, half_height)),
|
||||
Rotation(angle=0)
|
||||
)
|
||||
new_cell.behavioral_model = new_cell.behavioral_model.mutate(3)
|
||||
|
||||
world.add_object(new_cell)
|
||||
|
||||
return world
|
||||
@ -91,7 +98,6 @@ class SimulationEngine:
|
||||
def run(self):
|
||||
while self.running:
|
||||
self._handle_frame()
|
||||
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
|
||||
@ -99,57 +105,16 @@ class SimulationEngine:
|
||||
deltatime = self.clock.get_time() / 1000.0
|
||||
tick_interval = 1.0 / self.input_handler.tps
|
||||
|
||||
# Handle events
|
||||
events = pygame.event.get()
|
||||
self.running = self.input_handler.handle_events(events, self.hud.manager)
|
||||
|
||||
for event in events:
|
||||
if event.type == pygame.VIDEORESIZE:
|
||||
self.window_width, self.window_height = event.w, event.h
|
||||
self.screen = pygame.display.set_mode((self.window_width, self.window_height),
|
||||
pygame.RESIZABLE)
|
||||
self._update_simulation_view()
|
||||
self.hud.update_layout(self.window_width, self.window_height)
|
||||
self._handle_window_events(events)
|
||||
|
||||
if self.input_handler.sprint_mode:
|
||||
# Sprint mode: run as many ticks as possible, skip rendering
|
||||
current_time = time.perf_counter()
|
||||
while True:
|
||||
self.input_handler.update_selected_objects()
|
||||
self.world.tick_all()
|
||||
self.tick_counter += 1
|
||||
self.total_ticks += 1
|
||||
# Optionally break after some time to allow event processing
|
||||
if time.perf_counter() - current_time > 0.05: # ~50ms per batch
|
||||
break
|
||||
# Update TPS every second
|
||||
if time.perf_counter() - self.last_tps_time >= 1.0:
|
||||
self.actual_tps = self.tick_counter
|
||||
self.tick_counter = 0
|
||||
self.last_tps_time = time.perf_counter()
|
||||
# No rendering or camera update
|
||||
|
||||
self.renderer.clear_screen()
|
||||
self.hud.render_sprint_debug(self.screen, self.actual_tps, self.total_ticks)
|
||||
pygame.display.flip()
|
||||
self.clock.tick(MAX_FPS)
|
||||
self._handle_sprint_mode()
|
||||
return
|
||||
|
||||
if not self.input_handler.is_paused:
|
||||
current_time = time.perf_counter()
|
||||
while current_time - self.last_tick_time >= tick_interval:
|
||||
self.last_tick_time += tick_interval
|
||||
self.tick_counter += 1
|
||||
self.total_ticks += 1
|
||||
|
||||
self.input_handler.update_selected_objects()
|
||||
self.world.tick_all()
|
||||
self.hud.manager.update(deltatime)
|
||||
|
||||
if current_time - self.last_tps_time >= 1.0:
|
||||
self.actual_tps = self.tick_counter
|
||||
self.tick_counter = 0
|
||||
self.last_tps_time += 1.0
|
||||
self._handle_simulation_ticks(tick_interval, deltatime)
|
||||
else:
|
||||
self.last_tick_time = time.perf_counter()
|
||||
self.last_tps_time = time.perf_counter()
|
||||
@ -158,25 +123,74 @@ class SimulationEngine:
|
||||
self._update(deltatime)
|
||||
self._render()
|
||||
|
||||
def _handle_window_events(self, events):
|
||||
for event in events:
|
||||
self.hud.process_event(event)
|
||||
if event.type == pygame.VIDEORESIZE:
|
||||
self.window_width, self.window_height = event.w, event.h
|
||||
self.screen = pygame.display.set_mode(
|
||||
(self.window_width, self.window_height),
|
||||
pygame.RESIZABLE
|
||||
)
|
||||
self._update_simulation_view()
|
||||
self.hud.update_layout(self.window_width, self.window_height)
|
||||
|
||||
self.hud.update_layout(self.window_width, self.window_height)
|
||||
self._update_simulation_view()
|
||||
|
||||
def _handle_sprint_mode(self):
|
||||
current_time = time.perf_counter()
|
||||
while True:
|
||||
self.input_handler.update_selected_objects()
|
||||
self.world.tick_all()
|
||||
self.tick_counter += 1
|
||||
self.total_ticks += 1
|
||||
if time.perf_counter() - current_time > 0.05:
|
||||
break
|
||||
if time.perf_counter() - self.last_tps_time >= 1.0:
|
||||
self.actual_tps = self.tick_counter
|
||||
self.tick_counter = 0
|
||||
self.last_tps_time = time.perf_counter()
|
||||
self.screen.fill(BLACK)
|
||||
self.renderer.clear_screen()
|
||||
self.hud.render_sprint_debug(self.screen, self.actual_tps, self.total_ticks)
|
||||
pygame.display.flip()
|
||||
self.clock.tick(MAX_FPS)
|
||||
|
||||
def _handle_simulation_ticks(self, tick_interval, deltatime):
|
||||
current_time = time.perf_counter()
|
||||
while current_time - self.last_tick_time >= tick_interval:
|
||||
self.last_tick_time += tick_interval
|
||||
self.tick_counter += 1
|
||||
self.total_ticks += 1
|
||||
self.input_handler.update_selected_objects()
|
||||
self.world.tick_all()
|
||||
self.hud.manager.update(deltatime)
|
||||
if current_time - self.last_tps_time >= 1.0:
|
||||
self.actual_tps = self.tick_counter
|
||||
self.tick_counter = 0
|
||||
self.last_tps_time += 1.0
|
||||
|
||||
def _update(self, deltatime):
|
||||
keys = pygame.key.get_pressed()
|
||||
self.input_handler.update_camera(keys, deltatime)
|
||||
|
||||
def _render(self):
|
||||
self.renderer.clear_screen(self.screen)
|
||||
self.renderer.draw_grid(self.camera, self.input_handler.show_grid)
|
||||
self.renderer.render_world(self.world, self.camera)
|
||||
self.renderer.render_interaction_radius(self.world, self.camera, self.input_handler.selected_objects, self.input_handler.show_interaction_radius)
|
||||
self.renderer.render_selection_rectangle(self.input_handler.get_selection_rect(), self.sim_view_rect)
|
||||
self.renderer.render_selected_objects_outline(self.input_handler.selected_objects, self.camera)
|
||||
self.screen.fill(BLACK)
|
||||
self.renderer.clear_screen()
|
||||
|
||||
# In core/simulation_engine.py, in _render():
|
||||
self.screen.blit(self.sim_view, (self.sim_view_rect.left, self.sim_view_rect.top))
|
||||
if not self.hud.dragging_splitter:
|
||||
self.renderer.draw_grid(self.camera, self.input_handler.show_grid)
|
||||
self.renderer.render_world(self.world, self.camera)
|
||||
self.renderer.render_interaction_radius(
|
||||
self.world, self.camera, self.input_handler.selected_objects, self.input_handler.show_interaction_radius
|
||||
)
|
||||
self.renderer.render_selection_rectangle(self.input_handler.get_selection_rect(), self.sim_view_rect)
|
||||
self.renderer.render_selected_objects_outline(self.input_handler.selected_objects, self.camera)
|
||||
self.screen.blit(self.sim_view, (self.sim_view_rect.left, self.sim_view_rect.top))
|
||||
|
||||
# Draw border around sim_view
|
||||
border_color = (255, 255, 255) # White
|
||||
border_width = 3
|
||||
pygame.draw.rect(self.screen, border_color, self.sim_view_rect, border_width)
|
||||
self.hud.manager.draw_ui(self.screen)
|
||||
self.hud.draw_splitters(self.screen) # <-- Add this line
|
||||
|
||||
self.hud.render_mouse_position(self.screen, self.camera, self.sim_view_rect)
|
||||
self.hud.render_fps(self.screen, self.clock)
|
||||
@ -185,9 +199,8 @@ class SimulationEngine:
|
||||
self.hud.render_selected_objects_info(self.screen, self.input_handler.selected_objects)
|
||||
self.hud.render_legend(self.screen, self.input_handler.show_legend)
|
||||
self.hud.render_pause_indicator(self.screen, self.input_handler.is_paused)
|
||||
|
||||
if self.input_handler.selected_objects:
|
||||
self.hud.render_neural_network_visualization(self.screen, self.input_handler.selected_objects[0])
|
||||
|
||||
pygame.display.flip()
|
||||
self.clock.tick(MAX_FPS)
|
||||
self.clock.tick(MAX_FPS)
|
||||
5
main.py
5
main.py
@ -1,5 +1,8 @@
|
||||
from core.simulation_engine import SimulationEngine
|
||||
|
||||
if __name__ == "__main__":
|
||||
def main():
|
||||
engine = SimulationEngine()
|
||||
engine.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
210
ui/hud.py
210
ui/hud.py
@ -6,18 +6,188 @@ import pygame_gui
|
||||
from config.constants import *
|
||||
from world.base.brain import CellBrain, FlexibleNeuralNetwork
|
||||
from world.objects import DefaultCell
|
||||
from pygame_gui.elements import UIPanel
|
||||
import math
|
||||
|
||||
DARK_GRAY = (40, 40, 40)
|
||||
DARKER_GRAY = (25, 25, 25)
|
||||
|
||||
class HUD:
|
||||
def __init__(self, ui_manager, screen_width=SCREEN_WIDTH, screen_height=SCREEN_HEIGHT):
|
||||
self.font = pygame.font.Font("freesansbold.ttf", FONT_SIZE)
|
||||
self.legend_font = pygame.font.Font("freesansbold.ttf", LEGEND_FONT_SIZE)
|
||||
|
||||
self.manager = ui_manager
|
||||
self.screen_width = screen_width
|
||||
self.screen_height = screen_height
|
||||
|
||||
self.manager = ui_manager
|
||||
# Panel size defaults
|
||||
self.control_bar_height = 48
|
||||
self.inspector_width = 260
|
||||
self.properties_width = 320
|
||||
self.console_height = 120
|
||||
self.splitter_thickness = 6
|
||||
|
||||
self.dragging_splitter = None
|
||||
self._create_panels()
|
||||
|
||||
def _create_panels(self):
|
||||
# Top control bar
|
||||
self.control_bar = UIPanel(
|
||||
relative_rect=pygame.Rect(0, 0, self.screen_width, self.control_bar_height),
|
||||
manager=self.manager,
|
||||
object_id="#control_bar",
|
||||
)
|
||||
|
||||
# Left inspector
|
||||
self.inspector_panel = UIPanel(
|
||||
relative_rect=pygame.Rect(
|
||||
0, self.control_bar_height,
|
||||
self.inspector_width,
|
||||
self.screen_height - self.control_bar_height
|
||||
),
|
||||
manager=self.manager,
|
||||
object_id="#inspector_panel",
|
||||
)
|
||||
|
||||
# Right properties
|
||||
self.properties_panel = UIPanel(
|
||||
relative_rect=pygame.Rect(
|
||||
self.screen_width - self.properties_width,
|
||||
self.control_bar_height,
|
||||
self.properties_width,
|
||||
self.screen_height - self.control_bar_height
|
||||
),
|
||||
manager=self.manager,
|
||||
object_id="#properties_panel",
|
||||
)
|
||||
|
||||
# Bottom console
|
||||
self.console_panel = UIPanel(
|
||||
relative_rect=pygame.Rect(
|
||||
self.inspector_width,
|
||||
self.screen_height - self.console_height,
|
||||
self.screen_width - self.inspector_width - self.properties_width,
|
||||
self.console_height
|
||||
),
|
||||
manager=self.manager,
|
||||
object_id="#console_panel",
|
||||
)
|
||||
|
||||
self.panels = [
|
||||
self.control_bar,
|
||||
self.inspector_panel,
|
||||
self.properties_panel,
|
||||
self.console_panel
|
||||
]
|
||||
self.dragging_splitter = None
|
||||
|
||||
def get_viewport_rect(self):
|
||||
# Returns the rect for the simulation viewport
|
||||
x = self.inspector_width
|
||||
y = self.control_bar_height
|
||||
w = self.screen_width - self.inspector_width - self.properties_width
|
||||
h = self.screen_height - self.control_bar_height - self.console_height
|
||||
return pygame.Rect(x, y, w, h)
|
||||
|
||||
def update_layout(self, window_width, window_height):
|
||||
self.screen_width = window_width
|
||||
self.screen_height = window_height
|
||||
|
||||
# Control bar (top)
|
||||
self.control_bar.set_relative_position((0, 0))
|
||||
self.control_bar.set_dimensions((self.screen_width, self.control_bar_height))
|
||||
|
||||
# Inspector panel (left) - goes all the way to the bottom
|
||||
self.inspector_panel.set_relative_position((0, self.control_bar_height))
|
||||
self.inspector_panel.set_dimensions((self.inspector_width, self.screen_height - self.control_bar_height))
|
||||
|
||||
# Properties panel (right) - goes all the way to the bottom
|
||||
self.properties_panel.set_relative_position(
|
||||
(self.screen_width - self.properties_width, self.control_bar_height))
|
||||
self.properties_panel.set_dimensions((self.properties_width, self.screen_height - self.control_bar_height))
|
||||
|
||||
# Console panel (bottom, spans between inspector and properties)
|
||||
self.console_panel.set_relative_position((self.inspector_width, self.screen_height - self.console_height))
|
||||
self.console_panel.set_dimensions(
|
||||
(self.screen_width - self.inspector_width - self.properties_width, self.console_height))
|
||||
|
||||
def process_event(self, event):
|
||||
# Handle splitter dragging for resizing panels
|
||||
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
|
||||
mx, my = event.pos
|
||||
# Check if mouse is on a splitter (left/right/bottom)
|
||||
if abs(mx - self.inspector_width) < self.splitter_thickness and self.control_bar_height < my < self.screen_height - self.console_height:
|
||||
self.dragging_splitter = "inspector"
|
||||
elif abs(mx - (self.screen_width - self.properties_width)) < self.splitter_thickness and self.control_bar_height < my < self.screen_height - self.console_height:
|
||||
self.dragging_splitter = "properties"
|
||||
elif abs(my - (self.screen_height - self.console_height)) < self.splitter_thickness and self.inspector_width < mx < self.screen_width - self.properties_width:
|
||||
self.dragging_splitter = "console"
|
||||
self.update_layout(self.screen_width, self.screen_height)
|
||||
elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
|
||||
self.dragging_splitter = None
|
||||
elif event.type == pygame.MOUSEMOTION and self.dragging_splitter:
|
||||
mx, my = event.pos
|
||||
if self.dragging_splitter == "inspector":
|
||||
self.inspector_width = max(100, min(mx, self.screen_width - self.properties_width - 100))
|
||||
elif self.dragging_splitter == "properties":
|
||||
self.properties_width = max(100, min(self.screen_width - mx, self.screen_width - self.inspector_width - 100))
|
||||
elif self.dragging_splitter == "console":
|
||||
self.console_height = max(60, min(self.screen_height - my, self.screen_height - self.control_bar_height - 60))
|
||||
self.update_layout(self.screen_width, self.screen_height)
|
||||
|
||||
def draw_splitters(self, screen):
|
||||
# Draw draggable splitters for visual feedback
|
||||
indicator_color = (220, 220, 220)
|
||||
indicator_size = 6 # Length of indicator line
|
||||
indicator_gap = 4 # Gap between indicator lines
|
||||
indicator_count = 3 # Number of indicator lines
|
||||
|
||||
# Vertical splitter (inspector/properties)
|
||||
# Inspector/properties only if wide enough
|
||||
if self.inspector_width > 0:
|
||||
x = self.inspector_width - 2
|
||||
y1 = self.control_bar_height
|
||||
y2 = self.screen_height - self.console_height
|
||||
# Draw indicator (horizontal lines) in the middle
|
||||
mid_y = (y1 + y2) // 2
|
||||
for i in range(indicator_count):
|
||||
offset = (i - 1) * (indicator_gap + 1)
|
||||
pygame.draw.line(
|
||||
screen, indicator_color,
|
||||
(x - indicator_size // 2, mid_y + offset),
|
||||
(x + indicator_size // 2, mid_y + offset),
|
||||
2
|
||||
)
|
||||
|
||||
if self.properties_width > 0:
|
||||
x = self.screen_width - self.properties_width + 2
|
||||
y1 = self.control_bar_height
|
||||
y2 = self.screen_height - self.console_height
|
||||
mid_y = (y1 + y2) // 2
|
||||
for i in range(indicator_count):
|
||||
offset = (i - 1) * (indicator_gap + 1)
|
||||
pygame.draw.line(
|
||||
screen, indicator_color,
|
||||
(x - indicator_size // 2, mid_y + offset),
|
||||
(x + indicator_size // 2, mid_y + offset),
|
||||
2
|
||||
)
|
||||
|
||||
# Horizontal splitter (console)
|
||||
if self.console_height > 0:
|
||||
y = self.screen_height - self.console_height + 2
|
||||
x1 = self.inspector_width
|
||||
x2 = self.screen_width - self.properties_width
|
||||
mid_x = (x1 + x2) // 2
|
||||
for i in range(indicator_count):
|
||||
offset = (i - 1) * (indicator_gap + 1)
|
||||
pygame.draw.line(
|
||||
screen, indicator_color,
|
||||
(mid_x + offset, y - indicator_size // 2),
|
||||
(mid_x + offset, y + indicator_size // 2),
|
||||
2
|
||||
)
|
||||
|
||||
def render_mouse_position(self, screen, camera, sim_view_rect):
|
||||
"""Render mouse position in top left."""
|
||||
@ -145,6 +315,7 @@ class HUD:
|
||||
VIZ_WIDTH = 280 # Width of the neural network visualization area
|
||||
VIZ_HEIGHT = 300 # Height of the neural network visualization area
|
||||
VIZ_RIGHT_MARGIN = VIZ_WIDTH + 50 # Distance from right edge of screen to visualization
|
||||
VIZ_BOTTOM_MARGIN = 50 # Distance from the bottom of the screen
|
||||
|
||||
# Background styling constants
|
||||
BACKGROUND_PADDING = 30 # Padding around the visualization background
|
||||
@ -196,6 +367,9 @@ class HUD:
|
||||
TOOLTIP_MARGIN = 10
|
||||
TOOLTIP_LINE_SPACING = 0 # No extra spacing between lines
|
||||
|
||||
if self.properties_width < VIZ_RIGHT_MARGIN + 50:
|
||||
self.properties_width = VIZ_RIGHT_MARGIN + 50 # Ensure properties panel is wide enough for tooltip
|
||||
|
||||
if not hasattr(cell, 'behavioral_model'):
|
||||
return
|
||||
|
||||
@ -206,9 +380,9 @@ class HUD:
|
||||
|
||||
network: FlexibleNeuralNetwork = cell_brain.neural_network
|
||||
|
||||
# Calculate visualization position
|
||||
# Calculate visualization position (bottom right)
|
||||
viz_x = self.screen_width - VIZ_RIGHT_MARGIN # Right side of screen
|
||||
viz_y = (self.screen_height // 2) - (VIZ_HEIGHT // 2) # Centered vertically
|
||||
viz_y = self.screen_height - VIZ_HEIGHT - VIZ_BOTTOM_MARGIN # Above the bottom margin
|
||||
|
||||
layer_spacing = VIZ_WIDTH // max(1, len(network.layers) - 1) if len(network.layers) > 1 else VIZ_WIDTH
|
||||
|
||||
@ -218,6 +392,8 @@ class HUD:
|
||||
pygame.draw.rect(screen, BACKGROUND_COLOR, background_rect)
|
||||
pygame.draw.rect(screen, WHITE, background_rect, BACKGROUND_BORDER_WIDTH)
|
||||
|
||||
info = network.get_structure_info()
|
||||
|
||||
# Title
|
||||
title_text = self.font.render("Neural Network", True, WHITE)
|
||||
title_rect = title_text.get_rect()
|
||||
@ -225,6 +401,13 @@ class HUD:
|
||||
title_rect.top = viz_y - TITLE_TOP_MARGIN
|
||||
screen.blit(title_text, title_rect)
|
||||
|
||||
# Render network cost under the title
|
||||
cost_text = self.font.render(f"Cost: {info['network_cost']}", True, WHITE)
|
||||
cost_rect = cost_text.get_rect()
|
||||
cost_rect.centerx = title_rect.centerx
|
||||
cost_rect.top = title_rect.bottom + 4 # Small gap below the title
|
||||
screen.blit(cost_text, cost_rect)
|
||||
|
||||
# Get current activations by running a forward pass with current inputs
|
||||
input_values = [cell_brain.inputs[key] for key in cell_brain.input_keys]
|
||||
|
||||
@ -383,22 +566,6 @@ class HUD:
|
||||
label_rect.bottom = viz_y + VIZ_HEIGHT + LAYER_LABEL_BOTTOM_MARGIN
|
||||
screen.blit(label_text, label_rect)
|
||||
|
||||
# Draw network info
|
||||
info = network.get_structure_info()
|
||||
info_lines = [
|
||||
f"Layers: {info['total_layers']}",
|
||||
f"Neurons: {info['total_neurons']}",
|
||||
f"Connections: {info['total_connections']}",
|
||||
f"Network Cost: {info['network_cost']}",
|
||||
]
|
||||
|
||||
for i, line in enumerate(info_lines):
|
||||
info_text = self.legend_font.render(line, True, WHITE)
|
||||
info_rect = info_text.get_rect()
|
||||
info_rect.left = viz_x
|
||||
info_rect.top = viz_y + VIZ_HEIGHT + INFO_TEXT_TOP_MARGIN + i * INFO_TEXT_LINE_SPACING
|
||||
screen.blit(info_text, info_rect)
|
||||
|
||||
# --- Tooltip logic for neuron hover ---
|
||||
mouse_x, mouse_y = pygame.mouse.get_pos()
|
||||
tooltip_text = None
|
||||
@ -488,8 +655,3 @@ class HUD:
|
||||
screen.blit(header, header_rect)
|
||||
screen.blit(tps_text, tps_rect)
|
||||
screen.blit(ticks_text, ticks_rect)
|
||||
|
||||
def update_layout(self, window_width, window_height):
|
||||
"""Update HUD layout on window resize."""
|
||||
self.screen_width = window_width
|
||||
self.screen_height = window_height
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user