From 55c360977fd481d16093fafc314c5253f84b1dac Mon Sep 17 00:00:00 2001 From: Yonatan Hattav Date: Wed, 27 Nov 2024 13:52:25 +0100 Subject: [PATCH] Particles can interact (#27) * allow particles to interact with gravity * revert setting changes --- .../GravitySimulator/GravitySimulator.tsx | 45 +++++++------------ .../ParticleRenderer/ParticleRenderer.tsx | 6 +-- src/constants/physics.ts | 5 +++ src/types/particle.ts | 21 +++++++++ src/utils/physics/physicsUtils.ts | 32 ++++++++++--- 5 files changed, 69 insertions(+), 40 deletions(-) create mode 100644 src/types/particle.ts diff --git a/src/components/GravitySimulator/GravitySimulator.tsx b/src/components/GravitySimulator/GravitySimulator.tsx index f5a6cda..b59efd0 100644 --- a/src/components/GravitySimulator/GravitySimulator.tsx +++ b/src/components/GravitySimulator/GravitySimulator.tsx @@ -29,26 +29,14 @@ import { Scenario } from "../../types/scenario"; import { SettingOutlined } from "@ant-design/icons"; import { SaveScenarioModal } from "../SaveScenarioModal/SaveScenarioModal"; import { createShareableLink } from "../../utils/compression"; +import { Particle, ParticleMechanics, TrailPoint } from "../../types/particle"; -interface ParticleMechanics { - position: Point2D; - velocity: Point2D; - force: Force; - mass: number; - elasticity: number; -} - -interface Particle extends ParticleMechanics { - id: string; - color: string; - size: number; - showVectors: boolean; - trails: TrailPoint[]; -} - -interface TrailPoint extends Point2D { - timestamp: number; -} +const generatePastelColor = () => { + const r = Math.floor(Math.random() * 75 + 180); + const g = Math.floor(Math.random() * 75 + 180); + const b = Math.floor(Math.random() * 75 + 180); + return `rgb(${r}, ${g}, ${b})`; +}; interface GravitySimulatorProps { gravityRef: React.RefObject; @@ -63,13 +51,6 @@ interface SimulationScenario { particles: Array>; } -const generatePastelColor = () => { - const r = Math.floor(Math.random() * 75 + 180); - const g = Math.floor(Math.random() * 75 + 180); - const b = Math.floor(Math.random() * 75 + 180); - return `rgb(${r}, ${g}, ${b})`; -}; - export const GravitySimulator: React.FC = ({ gravityRef, pointerPos, @@ -157,14 +138,20 @@ export const GravitySimulator: React.FC = ({ const updateParticleMechanics = useCallback( ( - particle: ParticleMechanics & { trails: TrailPoint[] } + particle: ParticleMechanics & { trails: TrailPoint[] }, + allParticles: Array = [] ): ParticleMechanics => { + // Filter out the current particle from gravity calculations + const otherParticles = allParticles.filter((p) => p !== particle); + const calculatedForce = calculateTotalForce( particle.position, throttledPointerPos, gravityPoints, offset, - physicsConfig.POINTER_MASS + physicsConfig.POINTER_MASS, + otherParticles, + physicsConfig.PARTICLES_EXERT_GRAVITY ); const force = { @@ -232,7 +219,7 @@ export const GravitySimulator: React.FC = ({ setParticles((currentParticles) => currentParticles.map((particle) => { - const mechanics = updateParticleMechanics(particle); + const mechanics = updateParticleMechanics(particle, currentParticles); return { ...particle, ...mechanics }; }) ); diff --git a/src/components/ParticleRenderer/ParticleRenderer.tsx b/src/components/ParticleRenderer/ParticleRenderer.tsx index 65c35cc..fd9500f 100644 --- a/src/components/ParticleRenderer/ParticleRenderer.tsx +++ b/src/components/ParticleRenderer/ParticleRenderer.tsx @@ -1,11 +1,7 @@ import React, { useState } from "react"; import { motion } from "framer-motion"; import { drawArrow } from "../../utils/physics/vectorUtils"; -import { Point2D, Force } from "../../types/physics"; - -interface TrailPoint extends Point2D { - timestamp: number; -} +import { TrailPoint } from "../../types/particle"; interface ParticleRenderParams { position: Point2D; diff --git a/src/constants/physics.ts b/src/constants/physics.ts index 0086176..6a38c03 100644 --- a/src/constants/physics.ts +++ b/src/constants/physics.ts @@ -26,6 +26,7 @@ export const PHYSICS_CONFIG = { CONSTANT_FORCE_X: 0, CONSTANT_FORCE_Y: 0, SOLID_BOUNDARIES: true, + PARTICLES_EXERT_GRAVITY: false, } as const; export const SETTINGS_METADATA: Record< @@ -93,6 +94,10 @@ export const SETTINGS_METADATA: Record< type: "boolean", isDev: false, }, + PARTICLES_EXERT_GRAVITY: { + type: "boolean", + isDev: false, + }, } as const; export const PARTICLE_MODES = { diff --git a/src/types/particle.ts b/src/types/particle.ts new file mode 100644 index 0000000..48cb283 --- /dev/null +++ b/src/types/particle.ts @@ -0,0 +1,21 @@ +import { Point2D, Force } from "../utils/types/physics"; + +export interface ParticleMechanics { + position: Point2D; + velocity: Point2D; + force: Force; + mass: number; + elasticity: number; +} + +export interface TrailPoint extends Point2D { + timestamp: number; +} + +export interface Particle extends ParticleMechanics { + id: string; + color: string; + size: number; + showVectors: boolean; + trails: TrailPoint[]; +} diff --git a/src/utils/physics/physicsUtils.ts b/src/utils/physics/physicsUtils.ts index 087a11b..0262b60 100644 --- a/src/utils/physics/physicsUtils.ts +++ b/src/utils/physics/physicsUtils.ts @@ -1,4 +1,5 @@ import { Point2D, Force, GravityPoint } from "../types/physics"; +import { ParticleMechanics } from "../../types/particle"; // Basic physics calculations export const calculateDistance = (p1: Point2D, p2: Point2D): number => { @@ -51,6 +52,7 @@ export const calculateGravitationalForce = ( minDistance = 30, maxForce = 2 ): Force => { + console.log(x1, y1, x2, y2, mass); if (!isFinite(x1) || !isFinite(y1) || !isFinite(x2) || !isFinite(y2)) { return { fx: 0, fy: 0 }; } // TODO: see if we can check the isFinite on x1+y1+x2+y2, is it faster? @@ -84,19 +86,21 @@ export const calculateGravitationalForce = ( }; export const calculateTotalForce = ( - cursorPos: Point2D, + selfPosition: Point2D, pointerPos: Point2D, gravityPoints: GravityPoint[], offset: Point2D, - pointerMass = 50000 + pointerMass = 50000, + particles: Array = [], + particlesExertGravity = false ): Force => { let totalFx = 0; let totalFy = 0; // Add pointer gravitational pull const pointerForce = calculateGravitationalForce( - cursorPos.x, - cursorPos.y, + selfPosition.x, + selfPosition.y, pointerPos.x, pointerPos.y, pointerMass @@ -107,8 +111,8 @@ export const calculateTotalForce = ( // Add gravity points force gravityPoints.forEach((point) => { const force = calculateGravitationalForce( - cursorPos.x, - cursorPos.y, + selfPosition.x, + selfPosition.y, point.x + offset.x, point.y + offset.y, point.mass @@ -117,6 +121,22 @@ export const calculateTotalForce = ( totalFy += force.fy; }); + // Add particle gravity if enabled + if (particlesExertGravity) { + particles.forEach((particle) => { + const force = calculateGravitationalForce( + selfPosition.x, + selfPosition.y, + particle.position.x, + particle.position.y, + particle.mass + ); + console.log(force); + totalFx += force.fx; + totalFy += force.fy; + }); + } + return { fx: totalFx, fy: totalFy }; };