From f629c272f81d743be89595bf52f0187bb9a9f47d Mon Sep 17 00:00:00 2001 From: yhattav Date: Sat, 23 Nov 2024 19:29:38 +0100 Subject: [PATCH 1/5] button to extract a scenario --- .../GravitySimulator/GravitySimulator.tsx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/components/GravitySimulator/GravitySimulator.tsx b/src/components/GravitySimulator/GravitySimulator.tsx index b27ee17..6d841f5 100644 --- a/src/components/GravitySimulator/GravitySimulator.tsx +++ b/src/components/GravitySimulator/GravitySimulator.tsx @@ -22,6 +22,7 @@ import { BiReset } from "react-icons/bi"; import { motion } from "framer-motion"; import { BsPlayFill, BsPauseFill } from "react-icons/bs"; import { DebugData } from "../../types/Debug"; +import { AiOutlineExport } from "react-icons/ai"; interface ParticleMechanics { position: Point2D; @@ -50,6 +51,12 @@ interface GravitySimulatorProps { className?: string; } +interface SimulationScenario { + settings: typeof physicsConfig; + gravityPoints: GravityPoint[]; + particles: Array>; +} + const generatePastelColor = () => { const r = Math.floor(Math.random() * 75 + 180); const g = Math.floor(Math.random() * 75 + 180); @@ -319,6 +326,19 @@ export const GravitySimulator: React.FC = ({ setGravityPoints((points) => points.filter((_, i) => i !== index)); }, []); + const exportScenario = useCallback( + (e: React.MouseEvent) => { + e.stopPropagation(); + const scenario: SimulationScenario = { + settings: physicsConfig, + gravityPoints, + particles: particles.map(({ trails, force, ...particle }) => particle), + }; + console.log(JSON.stringify(scenario, null, 2)); + }, + [physicsConfig, gravityPoints, particles] + ); + return ( <> - + ); }; diff --git a/src/scenarios/defaults/galaxyCollision.ts b/src/scenarios/defaults/galaxyCollision.ts new file mode 100644 index 0000000..f36c354 --- /dev/null +++ b/src/scenarios/defaults/galaxyCollision.ts @@ -0,0 +1,88 @@ +export const galaxyCollision: Scenario = { + id: "galaxy-collision", + name: "Galaxy Collision", + description: + "Two star clusters on a collision course, creating chaos and beauty", + data: { + settings: { + NEW_PARTICLE_MASS: 0.01, + NEW_PARTICLE_ELASTICITY: 0.8, + FRICTION: 0.999, + DELTA_TIME: 0.0166666666666667, + POINTER_MASS: 250000, + SHOW_VELOCITY_ARROWS: true, + SHOW_FORCE_ARROWS: false, + CONSTANT_FORCE_X: 0, + CONSTANT_FORCE_Y: 0, + SOLID_BOUNDARIES: true, + }, + gravityPoints: [ + // First galaxy + { + x: 200, + y: 200, + label: "Galaxy 1 Core", + mass: 100000, + color: "#FF6B6B", + }, + { + x: 250, + y: 150, + label: "Star 1", + mass: 20000, + color: "#FF8E8E", + }, + { + x: 150, + y: 250, + label: "Star 2", + mass: 20000, + color: "#FF8E8E", + }, + // Second galaxy + { + x: 800, + y: 600, + label: "Galaxy 2 Core", + mass: 100000, + color: "#4ECDC4", + }, + { + x: 750, + y: 650, + label: "Star 3", + mass: 20000, + color: "#6BE5DC", + }, + { + x: 850, + y: 550, + label: "Star 4", + mass: 20000, + color: "#6BE5DC", + }, + ], + particles: [ + { + id: "p1", + position: { x: 300, y: 300 }, + velocity: { x: 40, y: 20 }, + mass: 0.01, + elasticity: 0.8, + color: "rgb(255, 107, 107, 0.7)", + size: 8, + showVectors: true, + }, + { + id: "p2", + position: { x: 700, y: 500 }, + velocity: { x: -30, y: -15 }, + mass: 0.01, + elasticity: 0.8, + color: "rgb(78, 205, 196, 0.7)", + size: 8, + showVectors: true, + }, + ], + }, +}; diff --git a/src/scenarios/defaults/index.ts b/src/scenarios/defaults/index.ts new file mode 100644 index 0000000..6c3cf42 --- /dev/null +++ b/src/scenarios/defaults/index.ts @@ -0,0 +1,10 @@ +import { Scenario } from "../../types/scenario"; +import { threeStars } from "./threeStars"; +import { orbitalDance } from "./orbitalDance"; +import { galaxyCollision } from "./galaxyCollision"; + +export const defaultScenarios: Scenario[] = [ + threeStars, + orbitalDance, + galaxyCollision, +]; diff --git a/src/scenarios/defaults/orbitalDance.ts b/src/scenarios/defaults/orbitalDance.ts new file mode 100644 index 0000000..3c5a6a6 --- /dev/null +++ b/src/scenarios/defaults/orbitalDance.ts @@ -0,0 +1,69 @@ +export const orbitalDance: Scenario = { + id: "orbital-dance", + name: "Orbital Dance", + description: + "A delicate balance of five stars creating a mesmerizing orbital pattern", + data: { + settings: { + NEW_PARTICLE_MASS: 0.01, + NEW_PARTICLE_ELASTICITY: 0.8, + FRICTION: 0.999, + DELTA_TIME: 0.0166666666666667, + POINTER_MASS: 250000, + SHOW_VELOCITY_ARROWS: false, + SHOW_FORCE_ARROWS: false, + CONSTANT_FORCE_X: 0, + CONSTANT_FORCE_Y: 0, + SOLID_BOUNDARIES: true, + }, + gravityPoints: [ + { + x: 500, + y: 400, + label: "Center", + mass: 80000, + color: "#FFD93D", + }, + { + x: 300, + y: 400, + label: "Orbit 1", + mass: 15000, + color: "#6BCB77", + }, + { + x: 700, + y: 400, + label: "Orbit 2", + mass: 15000, + color: "#4D96FF", + }, + { + x: 500, + y: 200, + label: "Orbit 3", + mass: 15000, + color: "#FF6B6B", + }, + { + x: 500, + y: 600, + label: "Orbit 4", + mass: 15000, + color: "#9D3C72", + }, + ], + particles: [ + { + id: "p1", + position: { x: 400, y: 300 }, + velocity: { x: 80, y: 40 }, + mass: 0.01, + elasticity: 0.8, + color: "rgb(255, 217, 61, 0.7)", + size: 8, + showVectors: true, + }, + ], + }, +}; diff --git a/src/scenarios/defaults/threeStars.ts b/src/scenarios/defaults/threeStars.ts new file mode 100644 index 0000000..8932624 --- /dev/null +++ b/src/scenarios/defaults/threeStars.ts @@ -0,0 +1,56 @@ +import { Scenario } from "../../types/scenario"; + +export const threeStars: Scenario = { + id: "three-stars", + name: "Three Stars", + description: "A classic setup with three stars of different masses", + data: { + settings: { + NEW_PARTICLE_MASS: 0.01, + NEW_PARTICLE_ELASTICITY: 0.8, + FRICTION: 0.999, + DELTA_TIME: 0.0166666666666667, + POINTER_MASS: 250000, + SHOW_VELOCITY_ARROWS: false, + SHOW_FORCE_ARROWS: false, + CONSTANT_FORCE_X: 0, + CONSTANT_FORCE_Y: 0, + SOLID_BOUNDARIES: true, + }, + gravityPoints: [ + { + x: 700, + y: 700, + label: "Heavy", + mass: 50000, + color: "#FF6B6B", + }, + { + x: 500, + y: 150, + label: "Medium", + mass: 30000, + color: "#4ECDC4", + }, + { + x: 350, + y: 250, + label: "Light", + mass: 10000, + color: "#45B7D1", + }, + ], + particles: [ + { + id: "eq1yy5csv", + position: { x: 733.57230867967, y: 139.49931883490225 }, + velocity: { x: 113.91853909196708, y: 53.684561005581706 }, + mass: 0.01, + elasticity: 0.8, + color: "rgb(224, 192, 198)", + size: 10, + showVectors: true, + }, + ], + }, +}; diff --git a/src/types/scenario.ts b/src/types/scenario.ts new file mode 100644 index 0000000..0b3e37f --- /dev/null +++ b/src/types/scenario.ts @@ -0,0 +1,38 @@ +export interface ScenarioData { + settings: { + NEW_PARTICLE_MASS: number; + NEW_PARTICLE_ELASTICITY: number; + FRICTION: number; + DELTA_TIME: number; + POINTER_MASS: number; + SHOW_VELOCITY_ARROWS: boolean; + SHOW_FORCE_ARROWS: boolean; + CONSTANT_FORCE_X: number; + CONSTANT_FORCE_Y: number; + SOLID_BOUNDARIES: boolean; + }; + gravityPoints: Array<{ + x: number; + y: number; + label: string; + mass: number; + color: string; + }>; + particles: Array<{ + id: string; + position: { x: number; y: number }; + velocity: { x: number; y: number }; + mass: number; + elasticity: number; + color: string; + size: number; + showVectors: boolean; + }>; +} + +export interface Scenario { + id: string; + name: string; + description: string; + data: ScenarioData; +} From a7b7c821f000b92df3eff91e7c5719e208ced7cd Mon Sep 17 00:00:00 2001 From: yhattav Date: Mon, 25 Nov 2024 12:07:21 +0100 Subject: [PATCH 3/5] fix issues with stars positioning when switching scenarios --- .../GravitySimulator/GravitySimulator.tsx | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/components/GravitySimulator/GravitySimulator.tsx b/src/components/GravitySimulator/GravitySimulator.tsx index 9b9723d..2b9be69 100644 --- a/src/components/GravitySimulator/GravitySimulator.tsx +++ b/src/components/GravitySimulator/GravitySimulator.tsx @@ -348,17 +348,30 @@ export const GravitySimulator: React.FC = ({ const handleSelectScenario = useCallback( (scenario: Scenario) => { - updateSettings(scenario.data.settings); - setGravityPoints(scenario.data.gravityPoints); - setParticles( - scenario.data.particles.map((particle) => ({ - ...particle, - trails: [{ ...particle.position, timestamp: Date.now() }], - force: { fx: 0, fy: 0 }, - })) - ); - setIsSimulationStarted(true); - setIsScenarioPanelOpen(false); + // First, ensure all gravity points have unique IDs + const newGravityPoints = scenario.data.gravityPoints.map((point) => ({ + ...point, + id: point.id || Math.random().toString(36).substr(2, 9), // Ensure each point has an ID + })); + + // Reset the simulation state + setParticles([]); + setGravityPoints([]); // Clear existing points first + + // Update settings and state in the next frame to ensure clean rendering + requestAnimationFrame(() => { + updateSettings(scenario.data.settings); + setGravityPoints(newGravityPoints); + setParticles( + scenario.data.particles.map((particle) => ({ + ...particle, + trails: [{ ...particle.position, timestamp: Date.now() }], + force: { fx: 0, fy: 0 }, + })) + ); + setIsSimulationStarted(true); + setIsScenarioPanelOpen(false); + }); }, [updateSettings] ); From a566b3fc571495c2f34e1d94ae7e4dcc81f79fa7 Mon Sep 17 00:00:00 2001 From: yhattav Date: Mon, 25 Nov 2024 12:10:02 +0100 Subject: [PATCH 4/5] fix a positioning problem when deleting as well --- src/components/GravitySimulator/GravitySimulator.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/GravitySimulator/GravitySimulator.tsx b/src/components/GravitySimulator/GravitySimulator.tsx index 2b9be69..626b8de 100644 --- a/src/components/GravitySimulator/GravitySimulator.tsx +++ b/src/components/GravitySimulator/GravitySimulator.tsx @@ -330,7 +330,16 @@ export const GravitySimulator: React.FC = ({ ); const handlePointDelete = useCallback((index: number) => { - setGravityPoints((points) => points.filter((_, i) => i !== index)); + setGravityPoints((currentPoints) => { + // Create a new array without the deleted point + const newPoints = currentPoints.filter((_, i) => i !== index); + + // Ensure each remaining point maintains its position and ID + return newPoints.map((point) => ({ + ...point, + id: point.id || Math.random().toString(36).substr(2, 9), // Ensure ID exists + })); + }); }, []); const exportScenario = useCallback( From 821ef5d4de29d723d41b3ec1ffd0992e41efb478 Mon Sep 17 00:00:00 2001 From: yhattav Date: Mon, 25 Nov 2024 12:16:22 +0100 Subject: [PATCH 5/5] styles for unused tab texts --- .../ScenarioPanel/ScenarioPanel.scss | 8 +++++-- .../ScenarioPanel/ScenarioPanel.tsx | 22 +++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/components/ScenarioPanel/ScenarioPanel.scss b/src/components/ScenarioPanel/ScenarioPanel.scss index 02cfe2e..e39f139 100644 --- a/src/components/ScenarioPanel/ScenarioPanel.scss +++ b/src/components/ScenarioPanel/ScenarioPanel.scss @@ -39,11 +39,15 @@ } :global(.ant-tabs-tab) { - color: rgba(255, 255, 255, 0.7); + color: rgba(255, 255, 255, 0.7) !important; padding: 8px 0; &:global(.ant-tabs-tab-active) { - color: rgba(255, 255, 255, 0.9); + color: rgba(255, 255, 255, 0.9) !important; + } + + &:hover { + color: rgba(255, 255, 255, 0.8) !important; } } diff --git a/src/components/ScenarioPanel/ScenarioPanel.tsx b/src/components/ScenarioPanel/ScenarioPanel.tsx index 4a06b84..c72c12b 100644 --- a/src/components/ScenarioPanel/ScenarioPanel.tsx +++ b/src/components/ScenarioPanel/ScenarioPanel.tsx @@ -72,7 +72,16 @@ export const ScenarioPanel: React.FC = ({ items={[ { key: "1", - label: Default, + label: ( + + Default + + ), children: (
{defaultScenarios.map((scenario) => ( @@ -107,7 +116,16 @@ export const ScenarioPanel: React.FC = ({ }, { key: "2", - label: Saved, + label: ( + + Saved + + ), children: (