Extends Boids flocking simulations to periodic 2D domains via rectangular lattice projections, eliminating edge effects through Mod-wrapped position updates and Nearest-driven force calculations across domain copies; integrates dynamic parameter controls (mobility rates, inertia, speed) via sliders, precomputed neighbor lookups for global friend/foe interactions, and memory-efficient inertial averaging for 1000+ agents.
In response to the request here: https://mathematica.stackexchange.com/q/312395
See other part here:
Boids 1: 3D dynamics, velocity-color mapping, and inertia-driven coordination
Boids 2: spherical projection with dynamic viewpoint tracking
See other part here:
Boids 1: 3D dynamics, velocity-color mapping, and inertia-driven coordination
Boids 2: spherical projection with dynamic viewpoint tracking
Function definitions
Function definitions
Make periodic copies of a position
In[]:=
perioidLocations[position_,domain:{length_,height_}]:={{0,0},{-length,-height},{-length,0},{-length,height},{0,-height},{0,height},{length,-height},{length,0},{length,height}}+Threaded[position]
Use Nearest to find which copy to interact with
In[]:=
boidForce[me_,other_,domain_]:=Block{copies=perioidLocations[other,domain],closest,distance,delta},{closest,distance}=Nearest[copies->{"Element","Distance"}][me][[1]];
closest-me
.0001+distance
Same thing, but with a precomputed nearest function
In[]:=
nearestForce[location_,nf_]:=Block{closest,distance},{closest,distance}=nf[location][[1]];
closest-location
.0001+distance
Initialize
Initialize
In[]:=
numberBoids=500;boidLocations=RandomPoint[boundary=Rectangle[{0,0},{length,height}={2,.5}],numberBoids];{friend,enemy}=RandomInteger[{1,numberBoids},{2,numberBoids}];{everyonesFriend,everyonesEnemy}=RandomInteger[{1,numberBoids},2]velocity=ConstantArray[{0,0},numberBoids];friendMobility=2;enemyMobility=1;globalFriendMobility=.02;globalEnemyMobility=0.01;mobilityFactor=.01;inertialFactor=0.5;
Out[]=
{1,233}
View in a separate window
View in a separate window
In[]:=
CreateDocument@Dynamic[Graphics[{FaceForm[],EdgeForm[Black],boundary,Point[Flatten[perioidLocations[#,{length,height}]&/@boidLocations,1]]},ImageSize->Large,PlotRange->{{-length,2length},{-height,2height}}]];
Some controls for parameters (this should all be in a DynamicModule)
Some controls for parameters (this should all be in a DynamicModule)
In[]:=
Grid[{{Row[{Style["Friend Mobility",12],Slider[Dynamic[friendMobility],{0,4}]}],Row[{Style["Enemy Mobility",12],Slider[Dynamic[enemyMobility],{0,4}]}]},{Row[{Style["Everyone's Friend Mobility",12],Slider[Dynamic[globalFriendMobility],{0,1}]}],Row[{Style["Everyone's Enemy Mobility",12],Slider[Dynamic[globalEnemyMobility],{0,1}]}]},{Row[{Style["Inertia Factor",12],Slider[Dynamic[inertialFactor],{0,1}]}],Row[{Style["Speed",12],Slider[Dynamic[mobilityFactor],{0,.1}]}]}},Alignment->Left,Frame->All]
Out[]=
Friend Mobility | Enemy Mobility |
Everyone's Friend Mobility | Everyone's Enemy Mobility |
Inertia Factor | Speed |
Run simulation
Run simulation
In[]:=
Do[If[RandomReal[]<.02,With[{switchMe=RandomInteger[{1,numberBoids}]},{friend[[switchMe]],enemy[[switchMe]]}=RandomInteger[{1,numberBoids},2]]];If[RandomReal[]<.05,{everyonesFriend,everyonesEnemy}=RandomInteger[{1,numberBoids},2]];vLast=velocity;nfEveryonesFriend=Nearest[perioidLocations[boidLocations[[everyonesFriend]],{length,height}]->{"Element","Distance"}];nfEveryonesEnemy=Nearest[perioidLocations[boidLocations[[everyonesEnemy]],{length,height}]->{"Element","Distance"}];velocity=mobilityFactor(friendMobilityMapThread[boidForce[#1,#2,{length,height}]&,{boidLocations,Extract[boidLocations,List/@friend]}]-enemyMobilityMapThread[boidForce[#1,#2,{length,height}]&,{boidLocations,Extract[boidLocations,List/@enemy]}]+globalFriendMobilityMap[nearestForce[#,nfEveryonesFriend]&,boidLocations]-globalEnemyMobilityMap[nearestForce[#,nfEveryonesEnemy]&,boidLocations]);vMean=(1-inertialFactor)velocity+inertialFactorvLast;boidLocations=Mod[#,{length,height}]&/@(boidLocations+vMean),10^6]
CITE THIS NOTEBOOK
CITE THIS NOTEBOOK
Boids 3: periodic domain eliminates edge effects via rectangular lattice projections
by W. Craig Carter
Wolfram Community, STAFF PICKS, June 24, 2025
https://community.wolfram.com/groups/-/m/t/3485229
by W. Craig Carter
Wolfram Community, STAFF PICKS, June 24, 2025
https://community.wolfram.com/groups/-/m/t/3485229