I wanted to try something like space time graph using replllers and attractors where a balls repelles the a certian part of plan in y direction like cusion regarding the mass it has but the i have use react three rapier fdor this
import { useEffect, useRef } from "react";
import { Environment, OrbitControls, Sphere } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import { Physics, RigidBody, useRapier } from "@react-three/rapier";
import { R3RapierBranding } from "r3-rapier-branding";
import { Attractor } from "@react-three/rapier-addons";
import { Suspense } from "react";
import Spinner from "./Spinner";
import "./styles.scss";
// Function to create a 2D array of positions
const create2DArray = () => {
const array2D = [];
for (let i = -20; i <= 20; i++) {
const row = [];
for (let j = -20; j <= 20; j++) {
row.push([i, -2, j]); // Store positions
}
array2D.push(row);
}
return array2D;
};
function Scene() {
const pos = create2DArray(); // Generate positions
const rapier = useRapier();
const originalPositions = useRef(pos); // Store original positions
// Custom effect to apply Y-direction repulsion and restoration
useEffect(() => {
const attractorPosition = { x: 0, y: 0, z: 0 }; // Position of your repeller
// This function will apply repulsion and restoration forces
const applyForces = () => {
pos.forEach((row, rowIndex) => {
row.forEach((position, colIndex) => {
const rigidBody = rapier.world.bodies[colIndex]; // Assuming colIndex corresponds to the body's index
if (rigidBody) {
const bodyPosition = rigidBody.translation(); // Get current position of the rigid body
// Calculate distance in the Y direction from the attractor
const distanceY = bodyPosition.y - attractorPosition.y;
// Repulsive force if within a certain range
const repulsiveForceMagnitude = 10; // Adjust this value as needed
if (Math.abs(distanceY) < 5) {
const repulsionForce = new rapier.Vector3(
0,
repulsiveForceMagnitude,
0
);
rigidBody.applyImpulse(repulsionForce); // Apply the repulsive impulse
}
// Restorative force toward original position
const originalPosition =
originalPositions.current[rowIndex][colIndex]; // Get original position
const restorationForceMagnitude = 5; // Adjust this value as needed
const distanceToOriginalY = bodyPosition.y - originalPosition[1]; // Calculate distance from original position
// Apply restorative force if further than a certain threshold from the original position
if (Math.abs(distanceToOriginalY) > 0.1) {
// Adjust threshold for better responsiveness
const restorationForce = new rapier.Vector3(
0,
-restorationForceMagnitude * Math.sign(distanceToOriginalY),
0
); // Y-direction restoration
rigidBody.applyImpulse(restorationForce); // Apply the restoration impulse
}
}
});
});
};
const interval = setInterval(applyForces, 100); // Apply forces every 100ms
return () => clearInterval(interval); // Cleanup on component unmount
}, [pos, rapier]);
return (
<group>
<Attractor position={0} strength={-1} range={3} />
<Attractor position={0} strength={-1} range={3} />
{pos.map((row, rowIndex) =>
row.map((position, colIndex) => (
<RigidBody
key={`${rowIndex}-${colIndex}`}
position={[position[0], position[1], position[2]]}
colliders="ball"
type="dynamic" // Change to "dynamic" to allow movement
>
<Sphere args={[0.3]}>
<meshPhysicalMaterial />
</Sphere>
</RigidBody>
))
)}
<OrbitControls />
</group>
);
}
export default function App() {
return (
<div className="App">
<R3RapierBranding title="Attractors" version="1.0.0">
<Suspense fallback={<Spinner />}>
<Canvas
shadows
camera={{
position: [-8, 4, 8],
}}
>
<Environment preset="studio" />
<fog attach="fog" args={["#000", 2, 100]} />
<Physics gravity={[0, 0, 0]} debug>
<Scene />
</Physics>
</Canvas>
</Suspense>
</R3RapierBranding>
</div>
);
}
but here the balls are keep repelling i want them to have the tendency to get back in their original position