reorganizations.
This commit is contained in:
parent
b2187693d7
commit
3059e17622
@ -1,2 +0,0 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
47
settings.py
47
settings.py
@ -1,47 +0,0 @@
|
|||||||
"""
|
|
||||||
#File Name: settings.py
|
|
||||||
|
|
||||||
Global settings and imports for the project.
|
|
||||||
|
|
||||||
This module defines various settings for the game engine, such as enabling or disabling the cursor, glow effect, gas effect, debug mode, and FPS display. It also provides a function to load particle properties from a JSON file.
|
|
||||||
|
|
||||||
The `engine_settings` dictionary contains the configurable settings for the game engine. These settings can be used to customize the behavior of the game.
|
|
||||||
|
|
||||||
The `load_particle_properties()` function attempts to load particle properties from a 'particles.json' file. If the file is not found or the JSON data is invalid, it returns an empty dictionary.
|
|
||||||
|
|
||||||
The `particle_properties` variable is initialized by calling `load_particle_properties()` when the module is imported.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
import pygame
|
|
||||||
import json
|
|
||||||
import random
|
|
||||||
import time
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
engine_settings = {
|
|
||||||
'pause_sim': True,
|
|
||||||
'enable_cursor': True,
|
|
||||||
'enable_glow': False,
|
|
||||||
'enable_gas_effect': True,
|
|
||||||
'enable_debug': False,
|
|
||||||
'enable_fps': True,
|
|
||||||
'enable_WVisuals': False,
|
|
||||||
'enable_PVisuals': False,
|
|
||||||
'enable_TempVisuals': False,
|
|
||||||
'outerwall': True,
|
|
||||||
# 'settings': True/False
|
|
||||||
}
|
|
||||||
|
|
||||||
# Load particle properties from JSON file
|
|
||||||
def load_particle_properties():
|
|
||||||
try:
|
|
||||||
with open('particles.json') as f:
|
|
||||||
return json.load(f)
|
|
||||||
except (FileNotFoundError, json.JSONDecodeError):
|
|
||||||
print("Error loading particles.json")
|
|
||||||
return {}
|
|
||||||
|
|
||||||
# Load particle properties once when module is imported
|
|
||||||
particle_properties = load_particle_properties()
|
|
||||||
|
|
||||||
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
0
src/config/__init__.py
Normal file
0
src/config/__init__.py
Normal file
74
src/config/settings.py
Normal file
74
src/config/settings.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
"""
|
||||||
|
#File Name: settings.py
|
||||||
|
|
||||||
|
Global settings and imports for the project.
|
||||||
|
|
||||||
|
This module defines various settings for the game engine, such as enabling or disabling the cursor, glow effect, gas effect, debug mode, and FPS display. It also provides a function to load particle properties from a JSON file.
|
||||||
|
|
||||||
|
The `engine_settings` dictionary contains the configurable settings for the game engine. These settings can be used to customize the behavior of the game.
|
||||||
|
|
||||||
|
The `load_particle_properties()` function attempts to load particle properties from a 'particles.json' file. If the file is not found or the JSON data is invalid, it returns an empty dictionary.
|
||||||
|
|
||||||
|
The `particle_properties` variable is initialized by calling `load_particle_properties()` when the module is imported.
|
||||||
|
"""
|
||||||
|
import cProfile
|
||||||
|
import pstats
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import pygame
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
engine_settings = {
|
||||||
|
'pause_sim': True,
|
||||||
|
'enable_cursor': True,
|
||||||
|
'enable_glow': False,
|
||||||
|
'enable_gas_effect': True,
|
||||||
|
'enable_debug': True,
|
||||||
|
'enable_fps': True,
|
||||||
|
'enable_WVisuals': False,
|
||||||
|
'enable_PVisuals': False,
|
||||||
|
'enable_TempVisuals': False,
|
||||||
|
'outerwall': False,
|
||||||
|
# 'settings': True/False
|
||||||
|
}
|
||||||
|
# For particles.json loading in settings.py:
|
||||||
|
particles_path = os.path.join(os.path.dirname(__file__), '..', 'part', 'particles.json')
|
||||||
|
|
||||||
|
|
||||||
|
# Load particle properties from JSON file
|
||||||
|
def load_particle_properties():
|
||||||
|
# Load core particles
|
||||||
|
particle_data = {}
|
||||||
|
print(f"Loading particles from {particles_path}")
|
||||||
|
# Core particles
|
||||||
|
try:
|
||||||
|
with open(particles_path, 'r') as f:
|
||||||
|
particle_data.update(json.load(f))
|
||||||
|
print(f"Loaded {len(particle_data)} core particles")
|
||||||
|
except (FileNotFoundError, json.JSONDecodeError) as e:
|
||||||
|
print(f"Error loading core particles: {e}")
|
||||||
|
|
||||||
|
# Load mods from mods directory
|
||||||
|
mods_path = os.path.join(os.path.dirname(__file__), '..', 'part', 'mods')
|
||||||
|
if os.path.exists(mods_path):
|
||||||
|
for filename in os.listdir(mods_path):
|
||||||
|
if filename.endswith('.json'):
|
||||||
|
mod_file = os.path.join(mods_path, filename)
|
||||||
|
try:
|
||||||
|
with open(mod_file, 'r') as f:
|
||||||
|
mod_data = json.load(f)
|
||||||
|
print(f"Loading mod: {filename}")
|
||||||
|
particle_data.update(mod_data)
|
||||||
|
print(f"Loaded {len(mod_data)} particles from {filename}")
|
||||||
|
except (FileNotFoundError, json.JSONDecodeError) as e:
|
||||||
|
print(f"Error loading mod {filename}: {e}")
|
||||||
|
|
||||||
|
return particle_data
|
||||||
|
|
||||||
|
# Load particle properties once when module is imported
|
||||||
|
particle_properties = load_particle_properties()
|
||||||
|
__all__ = ['pygame', 'np', 'random', 'time', 'engine_settings', 'particle_properties', 'cProfile', 'pstats', 'sys', 'os']
|
||||||
|
|
||||||
0
src/part/__init__.py
Normal file
0
src/part/__init__.py
Normal file
49
src/part/mods/test.json
Normal file
49
src/part/mods/test.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"wsand": {
|
||||||
|
"name": "Wet Sand",
|
||||||
|
"size": 1,
|
||||||
|
"hardness": 0.5,
|
||||||
|
"color": [200, 200, 25, 255],
|
||||||
|
"velocity": 0.5,
|
||||||
|
"mass": 0.5,
|
||||||
|
"conductivity": 0,
|
||||||
|
"heat_capacity": 1,
|
||||||
|
"flamability": 0.8,
|
||||||
|
"temperature": 20,
|
||||||
|
"explosive": false,
|
||||||
|
"explosion_radius": 0,
|
||||||
|
"explosion_color": [0, 0, 0],
|
||||||
|
"friction": 0.5,
|
||||||
|
"viscosity": 0.3,
|
||||||
|
"pressure": 0,
|
||||||
|
"melt": "sand",
|
||||||
|
"melt_temperature": 100,
|
||||||
|
"conductive": false,
|
||||||
|
"liquid": false,
|
||||||
|
"solid": true,
|
||||||
|
"is_gas": false
|
||||||
|
},
|
||||||
|
"ultratanium": {
|
||||||
|
"name": "Ultra Tanium",
|
||||||
|
"size": 1,
|
||||||
|
"hardness": 1000,
|
||||||
|
"velocity": 0.1,
|
||||||
|
"conductivity": 1,
|
||||||
|
"heat_capacity": 1,
|
||||||
|
"color": [255, 200, 255, 255],
|
||||||
|
"pressure": 100,
|
||||||
|
"explosive": true,
|
||||||
|
"explosion_radius": 15,
|
||||||
|
"explosion_color": [
|
||||||
|
255,
|
||||||
|
0,
|
||||||
|
255
|
||||||
|
],
|
||||||
|
"temperature": 10000,
|
||||||
|
"conductive": true,
|
||||||
|
"liquid": true,
|
||||||
|
"solid": true,
|
||||||
|
"is_gas": true,
|
||||||
|
"special": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,7 +17,7 @@
|
|||||||
"friction": 0.5,
|
"friction": 0.5,
|
||||||
"viscosity": 0,
|
"viscosity": 0,
|
||||||
"pressure": 0,
|
"pressure": 0,
|
||||||
"melt": "molten-Glass",
|
"melt": "molten-glass",
|
||||||
"melt_temperature": 1700,
|
"melt_temperature": 1700,
|
||||||
"conductive": false,
|
"conductive": false,
|
||||||
"liquid": false,
|
"liquid": false,
|
||||||
0
src/physics/__init__.py
Normal file
0
src/physics/__init__.py
Normal file
@ -8,18 +8,21 @@ This module implements a 2D particle simulation with physics, interactions, and
|
|||||||
Key Components:
|
Key Components:
|
||||||
--------------
|
--------------
|
||||||
1. Particle Class
|
1. Particle Class
|
||||||
- Handles individual particle properties and behaviors
|
- Handles individual particle properties and behaviors
|
||||||
- Supports multiple particle types (solid, liquid, gas)
|
- Supports multiple particle types (solid, liquid, gas)
|
||||||
- Manages temperature and state transitions
|
|
||||||
|
|
||||||
2. Simulation Class
|
2. Simulation Class
|
||||||
- Core simulation engine
|
- Core simulation engine
|
||||||
- Manages particle creation, movement and interactions
|
- Manages particle creation, movement and interactions
|
||||||
- Handles physics calculations and spatial partitioning
|
- Handles physics calculations and spatial partitioning
|
||||||
|
- Manages temperature and state transitions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#Load the imports. Pygame is what makes this even work and so simple may consider other engines for performance depends on learning curve.
|
#Load the imports.
|
||||||
from settings import random, time, particle_properties
|
from config.settings import random, time, particle_properties
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import math
|
||||||
|
|
||||||
# Load particle properties from json so we know what particles we got and how they should be simulated.
|
# Load particle properties from json so we know what particles we got and how they should be simulated.
|
||||||
class Particle:
|
class Particle:
|
||||||
@ -97,6 +100,7 @@ class Simulation:
|
|||||||
self.wind_zones = []
|
self.wind_zones = []
|
||||||
self.wind = [0.0, 0.0] # Global wind vector (x, y)
|
self.wind = [0.0, 0.0] # Global wind vector (x, y)
|
||||||
|
|
||||||
|
|
||||||
def reset_particle_count(self):
|
def reset_particle_count(self):
|
||||||
self.particle_count = 0
|
self.particle_count = 0
|
||||||
|
|
||||||
@ -121,7 +125,21 @@ class Simulation:
|
|||||||
if cell_key in self.spatial_grid:
|
if cell_key in self.spatial_grid:
|
||||||
self.spatial_grid[cell_key].discard((x, y))
|
self.spatial_grid[cell_key].discard((x, y))
|
||||||
return cell_key
|
return cell_key
|
||||||
|
|
||||||
|
|
||||||
|
def _get_neighbors_from_grid(self, x, y):
|
||||||
|
"""Get neighbors using spatial grid"""
|
||||||
|
cell_key = self.get_cell_key(x, y)
|
||||||
|
neighbors = []
|
||||||
|
|
||||||
|
# Check current and adjacent cells
|
||||||
|
for dx in [-1, 0, 1]:
|
||||||
|
for dy in [-1, 0, 1]:
|
||||||
|
check_key = (cell_key[0] + dx, cell_key[1] + dy)
|
||||||
|
if check_key in self.spatial_grid:
|
||||||
|
neighbors.extend(self.spatial_grid[check_key])
|
||||||
|
|
||||||
|
return neighbors
|
||||||
|
|
||||||
def update_spatial_grid(self): # this is where we update the spatial grid.
|
def update_spatial_grid(self): # this is where we update the spatial grid.
|
||||||
"""Update spatial grid for optimized collision detection"""
|
"""Update spatial grid for optimized collision detection"""
|
||||||
@ -136,7 +154,8 @@ class Simulation:
|
|||||||
cell_lists[cell_key].append((x, y))
|
cell_lists[cell_key].append((x, y))
|
||||||
|
|
||||||
self.spatial_grid = {k: set(v) for k, v in cell_lists.items()}
|
self.spatial_grid = {k: set(v) for k, v in cell_lists.items()}
|
||||||
|
|
||||||
|
|
||||||
def _check_dormant_state(self, x, y, particle):
|
def _check_dormant_state(self, x, y, particle):
|
||||||
key = (x, y)
|
key = (x, y)
|
||||||
if particle.particle_type == 'wall':
|
if particle.particle_type == 'wall':
|
||||||
@ -158,7 +177,8 @@ class Simulation:
|
|||||||
self.particle_movement_counter[key] = 0
|
self.particle_movement_counter[key] = 0
|
||||||
self.dormant_particles.discard(key)
|
self.dormant_particles.discard(key)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def handle_phase_transitions(self, particle, x, y): # this is where we handle all the phase transitions.
|
def handle_phase_transitions(self, particle, x, y): # this is where we handle all the phase transitions.
|
||||||
"""Handle all phase transitions for a particle"""
|
"""Handle all phase transitions for a particle"""
|
||||||
# Check evaporation
|
# Check evaporation
|
||||||
@ -187,6 +207,7 @@ class Simulation:
|
|||||||
if new_type in self.particle_properties:
|
if new_type in self.particle_properties:
|
||||||
self.transform_particle(x, y, new_type)
|
self.transform_particle(x, y, new_type)
|
||||||
|
|
||||||
|
|
||||||
def handle_particle_interactions(self, dt): # this is where we handle all the particle interactions.
|
def handle_particle_interactions(self, dt): # this is where we handle all the particle interactions.
|
||||||
"""Handle interactions between different particle types"""
|
"""Handle interactions between different particle types"""
|
||||||
for x, y in list(self.active_particles):
|
for x, y in list(self.active_particles):
|
||||||
@ -260,6 +281,7 @@ class Simulation:
|
|||||||
self.active_particles.add((new_x, new_y))
|
self.active_particles.add((new_x, new_y))
|
||||||
self.active_particles.discard((x, y))
|
self.active_particles.discard((x, y))
|
||||||
|
|
||||||
|
|
||||||
def add_wind_zone(self, x, y):
|
def add_wind_zone(self, x, y):
|
||||||
# Instead of creating particles, store wind zone data
|
# Instead of creating particles, store wind zone data
|
||||||
wind_zone = {
|
wind_zone = {
|
||||||
@ -299,15 +321,18 @@ class Simulation:
|
|||||||
fy += drag * particle.velocity[1]
|
fy += drag * particle.velocity[1]
|
||||||
|
|
||||||
# Check neighboring particles
|
# Check neighboring particles
|
||||||
neighbors = self._get_quick_neighbors(x, y)
|
neighbors = self._get_neighbors_from_grid(x, y)
|
||||||
for nx, ny in neighbors:
|
for nx, ny in neighbors:
|
||||||
if 0 <= nx < self.width and 0 <= ny < self.height:
|
if(nx, ny) != (x, y):
|
||||||
neighbor = self.particles[nx][ny]
|
if 0 <= nx < self.width and 0 <= ny < self.height:
|
||||||
if neighbor:
|
neighbor = self.particles[nx][ny]
|
||||||
self._apply_neighbor_forces(particle, neighbor, fx, fy)
|
if neighbor:
|
||||||
|
self._apply_neighbor_forces(particle, neighbor, fx, fy)
|
||||||
|
|
||||||
|
|
||||||
return fx, fy
|
return fx, fy
|
||||||
|
|
||||||
|
|
||||||
def _process_particle_batch(self, batch, dt):
|
def _process_particle_batch(self, batch, dt):
|
||||||
updates = []
|
updates = []
|
||||||
new_active = set()
|
new_active = set()
|
||||||
@ -356,16 +381,19 @@ class Simulation:
|
|||||||
|
|
||||||
return new_active
|
return new_active
|
||||||
|
|
||||||
|
|
||||||
def _get_quick_neighbors(self, x, y):
|
def _get_quick_neighbors(self, x, y):
|
||||||
"""Quick neighbor lookup without full spatial grid"""
|
"""Quick neighbor lookup without full spatial grid"""
|
||||||
return [(x+dx, y+dy) for dx, dy in [(-1,0), (1,0), (0,-1), (0,1)]]
|
return [(x+dx, y+dy) for dx, dy in [(-1,0), (1,0), (0,-1), (0,1)]]
|
||||||
|
|
||||||
|
|
||||||
def _apply_neighbor_forces(self, particle, neighbor, fx, fy):
|
def _apply_neighbor_forces(self, particle, neighbor, fx, fy):
|
||||||
"""Optimized neighbor force calculation"""
|
"""Optimized neighbor force calculation"""
|
||||||
if hasattr(neighbor, 'temperature') and hasattr(particle, 'temperature'):
|
if hasattr(neighbor, 'temperature') and hasattr(particle, 'temperature'):
|
||||||
temp_diff = neighbor.temperature - particle.temperature
|
temp_diff = neighbor.temperature - particle.temperature
|
||||||
fy += temp_diff * 0.05
|
fy += temp_diff * 0.05
|
||||||
|
|
||||||
|
|
||||||
def ignite_particle(self, particle): # this is where we ignite the particle.
|
def ignite_particle(self, particle): # this is where we ignite the particle.
|
||||||
"""Handle ignition and burning of flammable particles."""
|
"""Handle ignition and burning of flammable particles."""
|
||||||
if hasattr(particle, 'flamability') and particle.flamability > 0.5:
|
if hasattr(particle, 'flamability') and particle.flamability > 0.5:
|
||||||
@ -505,6 +533,7 @@ class Simulation:
|
|||||||
return particle.particle_type
|
return particle.particle_type
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def apply_gravity(self, dt): # this is where we apply gravity.
|
def apply_gravity(self, dt): # this is where we apply gravity.
|
||||||
"""Handle only gravity and basic particle movement"""
|
"""Handle only gravity and basic particle movement"""
|
||||||
self.spatial_grid.clear()
|
self.spatial_grid.clear()
|
||||||
@ -744,7 +773,8 @@ class Simulation:
|
|||||||
if key in self.dormant_particles:
|
if key in self.dormant_particles:
|
||||||
self.dormant_particles.discard(key)
|
self.dormant_particles.discard(key)
|
||||||
self.particle_movement_counter[key] = 0
|
self.particle_movement_counter[key] = 0
|
||||||
|
|
||||||
|
|
||||||
def track_tps(self):
|
def track_tps(self):
|
||||||
"""Track Ticks Per Second for simulation performance monitoring"""
|
"""Track Ticks Per Second for simulation performance monitoring"""
|
||||||
if not hasattr(self, '_tps_counter'):
|
if not hasattr(self, '_tps_counter'):
|
||||||
@ -766,19 +796,17 @@ class Simulation:
|
|||||||
|
|
||||||
|
|
||||||
def simulate_step(self, dt, engine_settings):
|
def simulate_step(self, dt, engine_settings):
|
||||||
"""Run a single step of the simulation"""
|
"""Run simulation step with spatial grid updates"""
|
||||||
|
|
||||||
|
self.update_spatial_grid()
|
||||||
|
|
||||||
active_list = list(self.active_particles)
|
active_list = list(self.active_particles)
|
||||||
batch_size = 1000
|
batch_size = 1024
|
||||||
|
|
||||||
for i in range(0, len(active_list), batch_size):
|
for i in range(0, len(active_list), batch_size):
|
||||||
batch = active_list[i:i + batch_size]
|
batch = active_list[i:i + batch_size]
|
||||||
self._process_particle_batch(batch, dt)
|
self._process_particle_batch(batch, dt)
|
||||||
|
|
||||||
# Update spatial grid only when needed
|
|
||||||
if len(self.active_particles) > 100:
|
|
||||||
self.update_spatial_grid()
|
|
||||||
|
|
||||||
# Update particle positions and physics
|
# Update particle positions and physics
|
||||||
self.apply_gravity(dt)
|
self.apply_gravity(dt)
|
||||||
self.apply_physics(dt, engine_settings)
|
self.apply_physics(dt, engine_settings)
|
||||||
0
src/rendering/__init__.py
Normal file
0
src/rendering/__init__.py
Normal file
@ -22,8 +22,9 @@ The `clear_screen` function is used to reset the simulation grid and clear the d
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from settings import pygame, random, particle_properties, engine_settings
|
from config.settings import pygame, random, particle_properties, engine_settings
|
||||||
|
from typing import List, Dict
|
||||||
|
import colorsys
|
||||||
|
|
||||||
class Rendering:
|
class Rendering:
|
||||||
|
|
||||||
@ -11,19 +11,22 @@ 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.
|
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 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.
|
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.
|
The main loop runs at a target frame rate of 60 FPS (this fps varies on my mood and the testing), with the actual frame rate displayed in the debug overlay.
|
||||||
"""
|
"""
|
||||||
import cProfile
|
|
||||||
import pstats
|
# Import Require files for the Engine.
|
||||||
from settings import pygame, engine_settings
|
from config.settings import pygame, cProfile, pstats, engine_settings
|
||||||
from rendering import Rendering
|
|
||||||
|
from rendering.rendering import Rendering
|
||||||
|
from physics.sim import Simulation
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This is for the future physics engine until i figure out a better method used for testing right now.
|
This is for the future physics engine until i figure out a better method used for testing right now.
|
||||||
#import os
|
#import os
|
||||||
#import sys
|
#import sys
|
||||||
#sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
#sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
"""
|
"""
|
||||||
from sim import Simulation
|
|
||||||
|
|
||||||
def update_simulation(sim, dt, engine_settings):
|
def update_simulation(sim, dt, engine_settings):
|
||||||
"""Update simulation state"""
|
"""Update simulation state"""
|
||||||
@ -178,7 +181,7 @@ def main():
|
|||||||
screen.fill((0, 0, 0))
|
screen.fill((0, 0, 0))
|
||||||
|
|
||||||
fps = clock.get_fps()
|
fps = clock.get_fps()
|
||||||
dt = clock.tick(1000) / 1000
|
dt = clock.tick(60) / 1000
|
||||||
keys = pygame.key.get_pressed()
|
keys = pygame.key.get_pressed()
|
||||||
mouse_pos = pygame.mouse.get_pos()
|
mouse_pos = pygame.mouse.get_pos()
|
||||||
zoom_active = keys[pygame.K_z]
|
zoom_active = keys[pygame.K_z]
|
||||||
0
src/ui/__init__.py
Normal file
0
src/ui/__init__.py
Normal file
Loading…
x
Reference in New Issue
Block a user